sistema de desarrollo para un microprocesador … · 2 estudio de los trabajos existentes /...
TRANSCRIPT
PROYECTO FIN DE CARRERA
SISTEMA DE DESARROLLO PARA UN MICROPROCESADOR ORIENTADO A APLICACIONES AEROESPACIALES
DIRECTOR: Jose Daniel Muñoz Frías
AUTOR: Alberto Requena Izard
MADRID, Junio de 2009
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
INGENIERO INDUSTRIAL
ÍNDICE DE CONTENIDOS
MEMORIA. ÍNDICE DE CONTENIDOS 1
Parte I Memoria ......................................................................................... 5
Capítulo 1 Introducción ............................................................................... 6
1 Estructura del sistema con el que se trabaja ................................................. 7
2 Estudio de los trabajos existentes / tecnologías existentes ........................ 9
3 Motivación del proyecto................................................................................... 9
4 Objetivos ........................................................................................................... 10
4.1 Objetivos para el ensamblador ................................................................................... 10
4.2 Objetivos para el simulador ........................................................................................ 10
4.3 Objetivos para la interfaz gráfica................................................................................ 11
5 Metodología / Solución desarrollada........................................................... 11
6 Recursos / herramientas empleadas ............................................................. 11
Capítulo 2 Ensamblador ............................................................................ 13
Capítulo 3 Simulador ................................................................................. 17
1 Introducción...................................................................................................... 17
2 Estructura general ............................................................................................ 18
2.1 Clase sim........................................................................................................................ 18
2.2 Clase sys......................................................................................................................... 18
2.3 Clase dsp........................................................................................................................ 18
2.4 Clase tm ......................................................................................................................... 19
2.5 Clase apb........................................................................................................................ 19
2.6 Clase apb_slave............................................................................................................. 19
2.7 Clase var ........................................................................................................................ 19
3 Clase dsp............................................................................................................ 20
3.1 Datos principales .......................................................................................................... 20
3.2 Funciones principales .................................................................................................. 21
4 Clase tm (Task Manager)................................................................................ 24
4.1 Datos principales .......................................................................................................... 24
4.2 Funciones principales .................................................................................................. 25
5 Clase apb (Advanced Peripheral Bus) ......................................................... 27
5.1 Datos principales .......................................................................................................... 27
MEMORIA. ÍNDICE DE CONTENIDOS 2
5.2 Funciones principales .................................................................................................. 28
6 Clase apb_slave y clases derivadas .............................................................. 30
6.1 Clase apb_mem............................................................................................................. 30
6.2 Clase apb_seq ................................................................................................................ 31
6.3 Clase apb_timed ........................................................................................................... 32
7 Clase var ............................................................................................................ 33
7.1 Datos principales .......................................................................................................... 33
7.2 Funciones principales .................................................................................................. 34
8 Clase sys ............................................................................................................ 37
8.1 Funciones ....................................................................................................................... 37
9 Clase sim............................................................................................................ 39
9.1 Datos principales .......................................................................................................... 39
9.2 Funciones principales .................................................................................................. 40
10 Comunicación del simulador ........................................................................ 47
10.1 Modo interactivo normal........................................................................................... 48
10.2 Modo entrada por fichero, salida por ventana ....................................................... 48
10.3 Modo entrada por fichero, salida por fichero......................................................... 49
10.4 Modo interactivo por tuberías con la Interfaz Gráfica .......................................... 49
11 Estructura del main ......................................................................................... 50
Capítulo 4 Interfaz Gráfica ....................................................................... 51
1 Introducción...................................................................................................... 51
1.1 Para qué una interfaz gráfica ...................................................................................... 51
1.2 wxWidgets....................................................................................................................... 51
2 Comunicación con los programas. Clase Console ..................................... 52
2.1 Comunicación con el ensamblador ............................................................................ 53
2.2 Comunicación con el simulador ................................................................................. 53
2.3 Datos principales de la clase console ......................................................................... 54
2.4 Funciones principales de la clase console ................................................................. 55
3 Diálogo de configuración............................................................................... 63
3.1 Estructuración en el programa ................................................................................... 64
3.2 Clase configure_panel.................................................................................................. 66
4 Panel del procesador ....................................................................................... 74
MEMORIA. ÍNDICE DE CONTENIDOS 3
4.1 Datos principales .......................................................................................................... 75
4.2 Funciones principales .................................................................................................. 75
5 Panel del programa.......................................................................................... 78
5.1 Datos principales .......................................................................................................... 79
5.2 Funciones principales .................................................................................................. 79
6 Panel de registros............................................................................................. 81
6.1 Datos principales .......................................................................................................... 82
6.2 Funciones principales .................................................................................................. 83
7 Panel de mensajes............................................................................................ 86
7.1 Funciones de manejo de eventos ................................................................................ 87
8 Panel principal ................................................................................................. 87
9 Marco principal (“Main Frame”) .................................................................. 89
9.1 Datos principales .......................................................................................................... 90
9.2 Funciones principales .................................................................................................. 90
9.3 Funciones de manejo de eventos ................................................................................ 91
Capítulo 5 Resultados / Experimentos ..................................................... 96
1 Datos de entrada .............................................................................................. 96
2 Ejecutando instrucciones................................................................................ 99
3 Ficheros de entrada........................................................................................ 101
3.1 Archivo con el código ensamblador, Prueba.asm .................................................... 101
3.2 Archivo con los datos de entrada de la memoria tipo “timed”, Timed.apbin ..... 103
3.3 Archivo con los datos de entrada del esclavo secuencial 1, in_seq_1.apbin......... 103
3.4 Archivo con los datos de entrada del esclavo secuencial 2, in_seq_2.apbin......... 103
4 Ficheros generados por el programa .......................................................... 104
4.1 Archivo de proyecto, Prueba.dspp ............................................................................. 104
4.2 Archivo de “backannotation”, test.back ................................................................... 105
4.3 Archivo con la ROM en vhdl, test.vhdl..................................................................... 107
4.4 Archivo con la salida del esclavo secuencial 1, out_seq_1.apbout ......................... 109
4.5 Archivo con la salida del esclavo secuencial 2, out_seq_2.apbout ......................... 109
Capítulo 6 Conclusiones .......................................................................... 110
Capítulo 7 Futuros desarrollos................................................................ 111
MEMORIA. ÍNDICE DE CONTENIDOS 4
1 Pequeños cambios ......................................................................................... 111
1.1 Adaptar a cambios en códigos de operación y ciclos de reloj sin necesidad de
recompilar.......................................................................................................................... 111
1.2 Mejorar la escritura de código en la interfaz gráfica ............................................. 112
1.3 Implementar las operaciones de la FPU manualmente......................................... 112
2 Grandes cambios............................................................................................ 113
2.1 Co-simulación con ModelSim .................................................................................... 113
2.2 Adaptación del compilador GCC ............................................................................. 113
2.3 Generación de código directamente con Simulink.................................................. 114
Parte II Manuales de usuario ................................................................. 115
Capítulo 1 Manual del Ensamblador...................................................... 116
Capítulo 2 Manual del Simulador........................................................... 119
Capítulo 3 Manual de la Interfaz Gráfica.............................................. 123
Capítulo 4 Manual para adaptar el sistema de desarrollo a distintos
proyectos ................................................................................................. 128
1 Qué hace falta recompilar y cómo .............................................................. 128
1.1 Cómo recompilar el ensamblador ............................................................................ 129
1.2 Cómo recompilar el simulador................................................................................. 129
2 Cambiar ciclos de reloj de cada instrucción ............................................. 129
3 Cambiar códigos de operación .................................................................... 129
4 Cambiar el set de instrucciones .................................................................. 130
4.1 Cambiar el fichero de entrada del programa bison ................................................ 130
4.2 Cambiar el fichero de entrada del programa flex ................................................... 131
4.3 Cambiar los ficheros dsp_inst.h y dsp_inst.c............................................................. 131
4.4 Cambiar el simulador................................................................................................. 132
Bibliografía ................................................................................................... 133
Parte III Estudio económico .................................................................... 135
Parte I MEMORIA
MEMORIA. INTRODUCCIÓN 6
Capítulo 1 INTRODUCCIÓN
Un DSP (Digital Signal Processor) es un procesador de señales digitales.
Mientras que un microprocesador está preparado para trabajar con
grandes bloques de software y muchas tareas simultáneamente, un DSP
está específicamente diseñado para altas necesidades de cálculo. Sin
embargo, el diseño de un simulador para un microprocesador o para un
DSP es prácticamente idéntico.
El departamento Microelectrónica de EADS Astrium CRISA, empresa con
la que se ha realizado el proyecto, diseña electrónica para el espacio. A
menudo se quiere diseñar un DSP para que vaya incluido en la FPGA, por
motivos de espacio. Este proyecto trata de facilitar el desarrollo de
software para los mismos, mejorando las herramientas que utilizaban para
ello. La parte concreta del desarrollo del software un DSP en la que se ha
trabajado es en la simulación del código binario que entiende éste.
Figura 1. Partes del sistema de desarrollo.
El sistema de desarrollo está dividido en las tres partes que se aprecian en
la Figura 1. En el Capítulo 2 se habla muy brevemente del ensamblador y
las pequeñas modificaciones que se le han realizado, en el Capítulo 3 se
discute el simulador del DSP, y el Capítulo 4 trata sobre la interfaz gráfica
que facilita y agiliza tanto el ensamblado como la simulación. El resto de
MEMORIA. INTRODUCCIÓN 7
capítulos muestran resultados, conclusiones y posibles ampliaciones del
proyecto.
1 Estructura del sistema con el que se trabaja
Puesto que el proyecto trata sobre herramientas para apoyar el desarrollo
de un DSP, se ve la necesidad de detallar la estructura del sistema sobre el
que se trabaja antes de explicar cómo se ha simulado.
Figura 2. Estructura del sistema en la FPGA.
El sistema entero se implanta en una FPGA, de modo que se implementa
con hardware tres circuitos diferentes:
• Un DSP, que contiene la memoria del programa, los registros (256
posiciones de memoria) y una FPU (Floating Point Unit) en la que se
ejecutan los algoritmos. Además de comunicarse con el “Task
Manager” y el ABP que se comentan a continuación recibe
directamente una palabra de 32 bits con la información más relevante
del exterior, que se usa con instrucciones especiales, como jmps, que
condiciona un salto al valor de uno de los bits de la palabra de status.
• Un circuito externo, el “Task Manager”, en el que se implementan por
hardware las distintas tareas que debe realizar el DSP, se decide cuál se
MEMORIA. INTRODUCCIÓN 8
debe ejecutar en cada momento y se manda la indicación al DSP. En el
proyecto sobre el que se trabaja, el DSP está encargado de cinco tareas
independientes del satélite:
o Selección del canal de conversión de ADC.
o Calibración del ADC.
o Ejecución y activación del algoritmo de control de la velocidad.
o Ejecución y activación del algoritmo de control de la posición.
o Ejecución y activación del algoritmo de supervivencia.
Son todas tareas que se deben ejecutar, siempre con el mismo periodo, y
siempre las mismas instrucciones, es por ello que se implementan en
una memoria ROM.
• Un sistema de comunicaciones con periféricos, el APB (Advanced
Peripheral Bus), que tiene mapeados en memoria a los dispositivos del
entorno, es decir, cada esclavo tiene asignadas unas posiciones de
memoria. Puesto que los esclavos (periféricos con los que se comunica
el DSP a través del APB) trabajan en coma fija y el DSP en coma
flotante, se produce una conversión al trasvasar información.
El sistema de desarrollo se ha intentado hacer tan fácil de adaptar como ha
sido posible, de modo que algunas cosas se pueden configurar sin
necesidad de tocar el código fuente, como el número de tareas, o el
tamaño de las memorias, y otras se han hecho de forma estructurada pero
para adaptarlo a otro proyecto habría que hacer pequeñas modificaciones
sobre el código fuente, como cambiar los ciclos de reloj de las instrucciones
o el set de instrucciones en sí. En la Parte IICapítulo 4 se ha escrito un
pequeño manual sobre como adaptar el código fuente ante los típicos
cambios para adaptar a distintos proyectos, o cambios en la aquitectura
del DSP.
MEMORIA. INTRODUCCIÓN 9
2 Estudio de los trabajos existentes / tecnologías existentes
El simulador de un microprocesador o de un DSP comercial es algo que
suelen hacer las propias empresas que lo fabrican y lo distribuyen, pues es
algo básico para su uso, por tanto se han encontrado muchos ejemplos en
Internet con los cuales hacerse una idea clara de lo que se busca. El
problema es que al no ser de código abierto no se ha podido reutilizar
nada de lo encontrado.
Lo que ha sido de gran ayuda es la versión anterior del simulador de la
propia empresa CRISA, realizado por D. Juan Antonio Ortega y por D.
José Daniel Muñoz Frías. Aunque estaban en lenguaje C, en vez de en
C++, algunas de las funciones principales que éste simulador realizaba
han mantenido su estructura.
3 Motivación del proyecto
Como ya se ha mencionado, la empresa CRISA desarrolla electrónica para
el espacio, y entre otras cosas, microprocesadores y DSPs. Puesto que la
herramienta que utilizaban para simular el diseño necesitaba algunas
modificaciones, surgió la idea de hacer un simulador en lenguaje C++ de
manera muy estructurada, y una interfaz gráfica que englobara la edición
del texto, el ensamblado, la simulación y la presentación de resultados.
Al tener una herramienta que facilita y acelera la simulación, se consigue
probar con mayor eficiencia el DSP que se está desarrollando y el
programa que se busca implementar. Si además esta herramienta está
diseñada pensando en su fácil modificación y adaptación a distintos
proyectos, se ahorrarán muchas horas de trabajo en futuros desarrollos de
microprocesadores y DSPs.
MEMORIA. INTRODUCCIÓN 10
4 Objetivos
El objetivo del proyecto es diseñar y realizar un sistema de desarrollo para
microprocesadores y DSPs para agilizar el diseño de los mismos y los
programas que usan. El diseño se centrará en una aplicación para un
proyecto concreto, en el que el set de instrucciones y la configuración
general del DSP está determinado, pero se intentará hacer lo más modular
posible, pensando en que la utilidad del programa se basa en su posible
aplicación a muchos proyectos.
4.1 Objetivos para el ensamblador
El ensamblador se debe adaptar al set de instrucciones nuevo, también
debe crear un fichero VHDL con la memoria ROM, para su simulación con
ModelSim y su posterior síntesis en la FPGA, y por último se debe poder
elegir ensamblar la memoria de registros en 24 o en 32 bits.
4.2 Objetivos para el simulador
• Su programación debe ser muy modular y clara, para adaptarlo
fácilmente a otros proyectos.
• Se deben poder simular tres tipos distintos de esclavos APB,
secuencial, memoria y memoria función del tiempo.
• El simulador se debe poder usar sin necesidad de la interfaz gráfica en
una ventana de comandos, y también se debe poder automatizar su
uso mediante ficheros de entrada y de salida.
• Se debe dejar abierta la posibilidad de simular comparando con el
resultado de la simulación con ModelSim, aunque no será el uso
principal del simulador.
• Se estudiará el realizar una portabilidad del GCC a la arquitectura
creada, permitiendo programar en lenguaje C en lugar de
ensamblador.
MEMORIA. INTRODUCCIÓN 11
4.3 Objetivos para la interfaz gráfica
La interfaz debe estar programada de forma modular, también para
facilitar modificaciones, y debe ser un ejecutable aparte del simulador.
Debe existir una ventana en la que escribir comandos directamente al
simulador.
5 Metodología / Solución desarrollada
Se crearán tres proyectos independientes del entorno de desarrollo
CodeBlocks, uno para cada ejecutable que se va a realizar.
• El ensamblador es una modificación del ya desarrollado, por lo que no
ocupa mucho tiempo.
• El simulador se realiza usando el lenguaje C++ basándose en el ya
realizado también por D. Jose Daniel Muñoz Frías y D. Juan Antonio
Ortega en lenguaje C.
• La interfaz gráfica se diseña partiendo de cero usando el “plugin” para
CodeBlocks llamado wxWidgets, especialmente pesado para el diseño de
interfaces gráficas.
Puesto que el proyecto es la razón de mi beca con la empresa CRISA, que
serán además los usuarios finales del programa realizado, los objetivos y
la metodología vienen definidos en gran parte por sus necesidades. Por
ello especialmente al principio del proyecto, en la etapa de en la que se
definen los objetivos y los métodos usados, es más adecuado trabajar
desde la propia empresa, más adelante cuando el tiempo se dedica
mayormente a programar basta con acercarse a CRISA una vez por
semana.
6 Recursos / herramientas empleadas
Todas las herramientas empleadas son de código abierto. Para los tres
ejecutables se ha usado el entorno de desarrollo CodeBlocks (en la
MEMORIA. INTRODUCCIÓN 12
referencia [1] se encuentra un enlace a la página oficial) junto con el
compilador GCC (enlace en la referencia [2]). Estos dos programas son
suficientes para el desarrollo del programa simulador, sin embargo para el
ensamblador y la interfaz son necesarios algunos más.
El ensamblador necesita de un analizador léxico, que se ha desarrollado
usando el programa flex (enlace para descarga en la referencia [3]) y un
analizador sintáctico, bison (enlace en la referencia [4]). Un tutorial sobre
su uso básico se puede encontrar en la referencia [5].
Para la interfaz gráfica se a usado wxWidgets, su funcionamiento básico se
explica brevemente en el Parte ICapítulo 41.2, donde también se
encuentran menciones a referencias con las páginas web útiles
relacionadas con el tema.
MEMORIA. ENSAMBLADOR 13
Capítulo 2 ENSAMBLADOR
El ensamblador es el programa que transforma el fichero de texto con el
código del programa en ficheros binarios con la información necesaria
para cargar el programa en la FPGA y para su análisis como la puede
entender la máquina.
Figura 3. Estructura interna del DSP.
La estructura por dentro del se puede apreciar en la Figura 3.Consta de
una FPU donde se realizan los cálculos, un banco de registros (el regfile),
el contador del programa, la bandera del sistema (C) para condicionales, la
memoria ROM donde se almacena el programa y una unidad de control.
En éste proyecto se ha tomado un ensamblador ya hecho por D. José
Daniel Muñoz Frías y D. Juan Antonio Ortega, al que se le han hecho
pequeñas modificaciones, que son:
• Cambio en el set de instrucciones que se ensambla, para dejarlo en las
siguientes funciones:
o nop: No hace nada, sólo incrementa en PC en 1.
MEMORIA. ENSAMBLADOR 14
o halt: Para la tarea actual, guarda el contexto y avisa al Task Manager.
o fin arg1, arg2: Mueve el dato de la dirección arg2 del APB a la
dirección arg1 del regfile.
o fout arg1, arg2: Mueve el dato de la dirección arg2 del regfile a la
dirección arg1 del APB.
o inout arg1, arg2: Mueve el dato de la dirección arg2 del APB a la
dirección arg1 del APB.
o finmul arg1, arg2, arg3: Escribe en la dirección arg1 del regfile el
resultado de lo que está en la dirección arg2 del APB multiplicado
por lo que está en la dirección arg3 del regfile.
o foutmul arg1, arg2, arg3: Escribe en la dirección arg1 del APB el
resultado de lo que está en la dirección arg2 del regfile multiplicado
por lo que está en la dirección arg3 del regfile.
o mov arg1, arg2: Mueve dentro del regfile el dato de la dirección arg2
a la dirección arg1.
o movc arg1, arg2: Mueve dentro del regfile el dato de la dirección arg2
a la dirección arg1 si la bandera del sistema está a 1.
o movnc arg1, arg2: Mueve dentro del regfile el dato de la dirección
arg2 a la dirección arg1 si la bandera del sistema está a 0.
o movgz arg1, arg2, arg3: Mueve dentro del regfile el dato de la
dirección arg2 a la dirección arg1 si arg3 es mayor que cero.
o movlz arg1, arg2, arg3: Mueve dentro del regfile el dato de la
dirección arg2 a la dirección arg1 si arg3 es menor que cero.
o cmpgt arg2, arg3: Compara dos registros y si arg2 es mayor que arg3
pone la bandera a 1.
o cmplt arg2, arg3: Compara dos registros y si arg2 es menor que arg3
pone la bandera a 1.
MEMORIA. ENSAMBLADOR 15
o cmpeq arg2, arg3: Compara dos registros y si arg2 es igual que arg3
pone la bandera a 1.
o cmpge arg2, arg3: Compara dos registros y si arg2 es mayor o igual
que arg3 pone la bandera a 1.
o cmple arg2, arg3: Compara dos registros y si arg2 es menor o igual
que arg3 pone la bandera a 1.
o jmp dst_jmp: Salta a la dirección de memoria dst_jmp.
o jmpc dst_jmp: Salta a la dirección de memoria dst_jmp si la bandera
vale 1.
o jmpnc dst_jmp: Salta a la dirección de memoria dst_jmp si la bandera
vale 0.
o jmps dst_jmp, arg3: Salta a la dirección de memoria dst_jmp si el bit
arg3 de la palabra de status vale 1.
o fadd arg1, arg2, arg3: Escribe en la dirección arg1 del regfile el
resultado de lo que está en la dirección arg2 más lo que está en la
dirección arg3 del regfile.
o fsub arg1, arg2, arg3: Escribe en la dirección arg1 del regfile el
resultado de lo que está en la dirección arg2 menos lo que está en la
dirección arg3 del regfile.
o fmul arg1, arg2, arg3: Escribe en la dirección arg1 del regfile el
resultado de lo que está en la dirección arg2 multiplicado por lo que
está en la dirección arg3 del regfile.
o fdiv arg1, arg2, arg3: Escribe en la dirección arg1 del regfile el
resultado de lo que está en la dirección arg2 dividido por lo que está
en la dirección arg3 del regfile.
o fsqrt arg1, arg2: Escribe en la dirección arg1 del regfile el resultado de
la raíz cuadrada de lo que está en la dirección arg2.
MEMORIA. ENSAMBLADOR 16
o fsin arg1, arg2: Escribe en la dirección arg1 del regfile el resultado del
seno de lo que está en la dirección arg2.
o fcos arg1, arg2: Escribe en la dirección arg1 del regfile el resultado del
coseno de lo que está en la dirección arg2.
o fsatp arg1, arg2, arg3: Si arg3 es mayor o igual que arg2, escribe en la
dirección arg1 del regfile lo que está en la dirección arg2 del regfile,
si no, escribe lo que está en la dirección arg3 del regfile.
o fsatn arg1, arg2, arg3: Si arg3 es menor o igual que arg2, escribe en la
dirección arg1 del regfile lo que está en la dirección arg2 del regfile,
si no, escribe lo que está en la dirección arg3 del regfile.
o fabs arg1, arg2: Escribe en la dirección arg1 del regfile el valor
absoluto de lo que está en la dirección arg2.
• La posibilidad de trabajar con registros de 24 o de 32 bits, pudiendo así
ser más flexibles en el compromiso entre precisión y espacio ocupado.
• La creación automática de un fichero vhdl que contiene la memoria
rom con las instrucciones ya codificadas, para permitir realizar
también la simulación en vhdl del programa.
Con éstas pequeñas adaptaciones el ensamblador se utiliza en el proyecto
tanto manualmente, como siendo llamado de manera automática por la
interfaz gráfica.
MEMORIA. SIMULADOR 17
Capítulo 3 SIMULADOR
1 Introducción
El simulador es un programa de ordenador que permite emular el
comportamiento del DSP (Digital Signal Processor) a lo largo de la
ejecución de un programa.
Permite por tanto obtener estadísticas del programa, (como por ejemplo el
tiempo que tarda en ejecutar una tarea) y del sistema simulado, facilitando
la tarea de probar posibles modificaciones en el diseño, de manera mucho
más rápida que cambiando el DSP en sí.
Figura 4. Estructura del simulador.
En la Figura 4 se presenta la estructura general del programa simulador.
Como cabe esperar, se aprecia una estructura muy parecida a la del
sistema emulado.
Se puede apreciar en la una clara estructura en el diseño del programa,
con unas partes contenidas en otras. La necesidad de esta estructuración es
lo que nos llevó a usar el lenguaje de programación C++. En el apéndice A
MEMORIA. SIMULADOR 18
se ofrece una breve introducción a la programación orientada a objetos, y
C++ en particular.
2 Estructura general
Se explica brevemente la estructura global del Simulador antes de entrar
en el proceso de diseño de cada parte, para dar una idea clara del
programa en su conjunto.
El simulador al completo está englobado en la clase sim, fuera de ella
quedan funciones necesarias para poder comunicar el objeto sim con las
peticiones realizadas al programa; éstas últimas funciones se presentan
después de las clases que componen el simulador
Las clases más importantes son las siguientes:
2.1 Clase sim
Esta clase contiene el sistema simulado (objeto sys) y el objeto var, los
métodos tanto para obtener los valores de las variables de simulador como
para ordenarle ejecutar, hace de interfaz con el sistema.
2.2 Clase sys
Engloba toda la parte más hardware del simulador. Por simplicidad y
buscando el máximo parecido con la realidad, tan sólo tiene dos métodos:
Init() y Step(). El primero inicializa todo el sistema, y el segundo ejecuta la
siguiente instrucción del programa, como en un microprocesador real.
2.3 Clase dsp
Contiene el objeto rom (el programa), el objeto regfile (variables) y la
información de las operaciones, aparte contiene el valor del Program
Counter, el reloj y el contexto de cada tarea. Alberga también la función
DecoAndExe(), encargada de decodificar y ejecutar cada instrucción.
MEMORIA. SIMULADOR 19
2.4 Clase tm
El Task Manager (tm) contiene los objetos de las tareas y la función
Schedule(), que accede a ésta información y decide cuál es la tarea que el
DSP debe ejecutar.
2.5 Clase apb
El Advanced Peripheral Bus (apb) es un bus de comunicaciones por el cual
el DSP obtiene información del exterior y a su vez deja sus resultados. Está
emulado como una memoria, compuesta por esclavos de tres tipos, que
son posibles dispositivos conectados al DSP. Contiene las funciones
CreateSlave(), que permite asignar a una zona de memoria un esclavo con
una información dada, y FindSlave(), que encuentra a qué esclavo le
corresponde la zona de memoria a la que se quiere acceder.
2.6 Clase apb_slave
A partir de ella se derivan las tres clases correspondientes a cada tipo de
esclavo, accesibles sólo a traves de la clase apb.
2.7 Clase var
Contiene información de las variables del programa, tanto su posición en
memoria como su valor esperado de la simulación del VHDL.
MEMORIA. SIMULADOR 20
3 Clase dsp
Figura 5. Elementos principales de la clase dsp.
El objeto dsp es la parte más importante del simulador, ya que tiene la
función principal (ejecutar una instrucción) y las memorias principales del
programa, además de los contextos de las tareas.
3.1 Datos principales
• Reloj del programa (clk_tick), para saber cuándo despertar una tarea,
por ejemplo.
• Program Counter del programa (PC).
• Id de la tarea en ejecución (current_task).
• Flags del programa, generados en instrucciones de comparación (b_gt,
b_lt, b_eq, b_ge, b_le).
• Vector con el contexto de cada tarea (tasks_context):
o Id de cada tarea del vector.
o PC por el que estaba ejecutando la tarea cuando se interrumpió.
o PC al que debe volver en caso de reset de la tarea (PC_reset).
• Punteros a los objetos apb, tm (task manager), rom y regfile. Necesarios
para poder acceder a sus datos y sus métodos
MEMORIA. SIMULADOR 21
• Nombre del fichero con la información para inicializar los Program
Counters de cada tarea (name_pc).
• Nombre del fichero de donde se lee la Status Word, dato de 32 bits
externo al DSP, que se simula con un fichero de texto externo
(name_status).
3.2 Funciones principales
3.2.1 DecoAndExe
Figura 6. Función DecoAndExe.
• Argumentos de entrada: ninguno.
• Argumentos de salida: 1 si se realiza un halt (se termina una tarea), 0 si
no.
• Función principal: Decodifica la instrucción de la memoria ROM a la
que apunta el PC y la ejecuta.
• Funcionamiento:
1. Lee PC.
2. Accede a la dirección de la ROM indicada en PC.
3. Separa el código de operación de los argumentos, mediante
máscaras.
MEMORIA. SIMULADOR 22
4. Con un switch, dependiendo del código de operación, accede al APB,
al regfile, realiza un salto, multiplica dos registros…, lo que
corresponda a la instrucción.
5. modifica el PC y el reloj del programa.
3.2.2 Status
Figura 7. Función Status.
• Argumentos de entrada: ninguno.
• Argumentos de salida: entero de 32 bits, con la palabra de status
• Función principal: devuelve el valor de la palabra de status
correspondiente al clk_tick actual.
MEMORIA. SIMULADOR 23
3.2.3 Halt
Figura 8. Función Halt.
• Argumentos de entrada: ninguno.
• Argumentos de salida: ninguno.
• Función principal: almacena el PC actual en el contexto de la tarea e
informa al task manager de que la tarea actual ha terminado.
3.2.4 Load
Figura 9. Función Load.
• Argumentos de entrada: id de la tarea a cargar.
• Argumentos de salida: ninguno.
MEMORIA. SIMULADOR 24
• Función principal: fuerza la carga del contexto de una tarea en
concreto.
4 Clase tm (Task Manager)
Figura 10. Elementos principales de la clase tm.
El objeto task manager es el encargado de decidir la tarea que se debe
ejecutar en cada momento. Está implementado fuera del DSP porque
también en realidad es un circuito externo.
4.1 Datos principales
• Vector de objetos task, cada uno de los cuales a su vez contienen:
o Id de la tarea.
o Prioridad de la tarea. En esta primera versión se toma como mayor
prioridad la tarea con identificador menor, pero está pensado para
poder realizar una ampliación en la que la
o Bit que indica si la tarea está o no activa (1/0).
o Estado de la tarea.
� RUNNING indica que la tarea es está ejecutando.
� READY indica que la tarea está lista para ejecutarse, y está
esperando a que acabe otra de mayor prioridad.
MEMORIA. SIMULADOR 25
� HALTED en el caso en el que la tarea está parada.
o Periodo de la tarea.
o Tick de reloj en el que se debe despertar la tarea, si está parada.
4.2 Funciones principales
4.2.1 Schedule
Figura 11. Función Schedule.
• Argumentos de entrada: Reloj del dsp
• Argumentos de salida: Id de la tarea a ejecutar.
• Función principal: Organiza las tareas en función de su estado y su
prioridad, y decide la tarea a ejecutar.
• Funcionamiento:
1. Comprueba si todas las tareas está paradas, de ser así, avanza el
reloj de ejecución hasta que a alguna le toque despertar.
2. Compara el reloj del sistema con el tick de reloj en el que cada tarea
debe despertar, y si procede, despierta la tarea.
3. Busca la tarea con mayor prioridad, que esté lista (en estado
READY).
4. Devuelve el id de esta tarea para que el dsp la ejecute.
MEMORIA. SIMULADOR 26
4.2.2 Init
�
Figura 12. Función Init.
• Argumentos de entrada: ninguno
• Argumentos de salida: ninguno
• Función principal: Inicializa las tareas, leyendo sus periodos de archivo
4.2.3 Halt
Figura 13. Función Halt.
• Argumentos de entrada: Id de la tarea y reloj actual del dsp
• Argumentos de salida: ninguno
• Función principal: Cuando se ejecuta una instrucción halt en el código,
duerme la tarea hasta el siguiente periodo
MEMORIA. SIMULADOR 27
5 Clase apb (Advanced Peripheral Bus)
Figura 14. Elementos principales de la clase apb.
El objeto apb es la puerta de comunicaciones del dsp hacia el entorno. Se
estructura como si fuera una memoria, cada esclavo (dispositivo
conectado al apb) tiene asignado un rango de direcciones de memoria y
para leer o escribir en él, simplemente se ha de hacer en la posición de
memoria que le corresponda en el apb.
5.1 Datos principales
• Tamaño del bus apb (apb_size), simplemente se necesita para poder
comprobar que los esclavos que se crean están dentro.
• Valor más alto de memoria usado (apb_max_used), se actualiza según se
crean esclavos en posiciones superiores de memoria, para cuando se
impriman los valores del apb dar sólo la información hasta la zona de
memoria usada.
• Un vector en el que se almacena información básica sobre los esclavos
(slaves_info), es decir:
o type, el tipo de esclavo, que puede ser:
� mem, que representa una memoria.
MEMORIA. SIMULADOR 28
� seq, que representa un esclavo de acceso sequencial, es decir, se le
pide un dato y te da el siguiente que tiene en la cola de entrada, o
le das un dato y lo guarda en la cola de salida.
� timed, que emula un esclavo que dará valores distintos
dependiendo de cuando se le pidan los datos, como por ejemplo
un conversor analógico-digital.
o start, la primera dirección de memoria correspondiente al esclavo.
o end, la última.
o slave_ptr, que es un puntero al esclavo, para usar sus propias
funciones de lectura y escritura.
5.2 Funciones principales
5.2.1 CreateSlave
Figura 15. Función CreateSlave.
• Argumentos de entrada: Tipo de esclavo, direcciones de comienzo y fin
del esclavo y nombres de los ficheros de entrada y de salida
• Argumentos de salida: Ninguno.
• Función principal: Crea un tipo de esclavo dado y guarda su
información básica en el vector slaves_info. Se le llama al configurar el
programa al iniciar.
MEMORIA. SIMULADOR 29
5.2.2 FindSlave
Figura 16. Función FindSlave.
• Argumentos de entrada: Dirección del apb buscada.
• Argumentos de salida: Puntero al esclavo del apb correspondiente, y
dirección dentro de este esclavo.
• Función principal: Permite desde fuera acceder para leer o escribir a
una dirección del apb sin tener información sobre el esclavo, usando
esta función para redirigir el acceso al que corresponda.
5.2.3 Resto de las funciones del apb
Figura 17. Resto de funciones del apb.
MEMORIA. SIMULADOR 30
Agrupo el resto de las funciones porque su funcionamiento es el mismo,
simplemente usan la función FindSlave para encontrar el esclavo al que
debe ser redirigidos, y luego usan la función correspondiente del esclavo.
6 Clase apb_slave y clases derivadas
Se ha creado una clase base, apb_slave, a partir de la cual se han derivado
las tres clases correspondientes a los tres tipos de esclavos. Esto permite
poder referirse a cualquiera de las tres clases con un puntero a clase
apb_slave, y usar las funciones definidas como virtuales en la clase base.
Figura 18. Elementos principales de la clase base apb_slave.
El ser las funciones virtuales en la clase base, su definición es distinta para
cada clase derivada, pero su uso es el mismo desde fuera, lo que simplifica
mucho su uso.
A continuación se describen las diferencias principales entre las tres clases
derivadas.
6.1 Clase apb_mem
Al llamar a la función Init se cargan en un vector los datos del fichero
externo, que contiene los valores de las posiciones de memoria distintas de
cero en el formato “dirección valor”, por ejemplo:
0000 3f80
0110 3f80
0114 bf80
MEMORIA. SIMULADOR 31
El fichero de entrada no se modifica, pero cada vez que se usa la función
Update se guarda el contenido de la memoria completa en el fichero
especificado de salida.
Las funciones de lectura y escritura funcionan de la manera que cabe
esperar de una memoria, sin nada especial. Se puede ver, sin embargo,
que existe una versión que transforma los datos a tipo float (las funciones
Read y Write), y otra versión que los deja como unsigned int (ReadNoConv y
WriteNoConv), esta última se usa tan sólo en la instrucción para mover
datos entre posiciones de la memoria, sin modificarlos.
6.2 Clase apb_seq
Este esclavo se comporta como si fueran dos colas de comunicaciones, una
de entrada y otra de salida. Al llamar a la función Init se cargan desde el
fichero los valores de la cola de entrada, que simplemente aparecen como
valores uno detrás de otro. Si hay un “0x” delante del número se entiende
como hexadecimal, si no como decimal, por ejemplo:
0x3f80
0x3f80
0xbf80
Cada vez que el dsp pide la lectura de un dato, se saca el primer dato de la
cola de entrada y se devuelve, y cada vez que se escribe un dato en el
esclavo, se guarda en el fichero de salida con el mismo formato que el de
entrada, se puede ver que por tanto la función Update no tiene que hacer
nada en absoluto.
La función de lectura tiene como entrada un bool con el que se le puede
indicar si debe extraer un dato de la cola o simplemente dar el que está en
la posición superior, sin extraer. Esto es así porque si se quiere leer un
dato para, por ejemplo, sacarlo por pantalla, no se debería modificar la
cola.
MEMORIA. SIMULADOR 32
También es posible crear el esclavo como una simple cola de entrada, no
pudiendo escribir en él, o como una simple cola de salida, en cuyo caso si
se intenta leer se leerá el último dato escrito.
La distinción entre las funciones que convierten los datos y las que no es
igual que en esclavo tipo memoria.
6.3 Clase apb_timed
Este esclavo es muy parecido a una memoria con la única diferencia de
que los datos que devuelve dependen de los ciclos de reloj del sistema.
Básicamente representa una memoria cuyos valores no solamente los
puede cambiar nuestro sistema, sino que también cambian de manera
externa. Los datos están en el siguiente formato:
“Ciclos de reloj” : “Posición de memoria” “valor” , “Posición” “valor” ,…
Por ejemplo:
0012 : 0040 3fa1 , 0056 4a46
0035 : 0089 0100
00b7 : 0040 3580 , 0056 4433 , 0058 3246
La función Init simplemente lee el fichero de entrada y actualiza lo que
corresponde a 0 ciclos de reloj. Es la función Update la que lee el fichero de
entrada cada vez, actualiza las posiciones de memoria que corresponda y
vuelca en un fichero externo en formato memoria los valores para que
puedan ser comprobados.
MEMORIA. SIMULADOR 33
7 Clase var
Figura 19. Elementos principales de la clase vars.
Una de las funcionalidades del simulador es comprobar una simulación
de VHDL. Es decir, tras obtener un fichero con los resultados de
simulación en el programa Modelsim, que muestra la evolución de las
variables al ejecutar el programa en el DSP, el simulador comprueba que
las variables dan los resultados correctos.
La clase var engloba toda la información sobre las variables necesaria para
realizar esta comprobación, el procedimiento se verá más a fondo en la
función CheckVHDL de la clase sim, pero básicamente guarda en un vector
lo que dice el fichero, y realiza su propia simulación y compara resultados.
7.1 Datos principales
• Un mapa de las variables var_map, para poder acceder rápidamente a
la dirección de memoria de la variable (dir), y a su tipo, que indica si la
variable pertenece al apb o al regfile (type).
• Una lista con tareas, y las variables que se consideran salidas de esta
tarea (task_outs). Como información de cada variable tendremos:
o name, el nombre de la variable.
o dir, su dirección en memoria.
MEMORIA. SIMULADOR 34
o value, el valor que la simulación con Modelsim ha obtenido.
o tolerance, la tolerancia admitida antes de indicar error entre los
resultados obtenidos por la simulación con nuestro programa y los
que ofrece Modelsim.
7.2 Funciones principales
7.2.1 Init
Figura 20. Función Init.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Carga el mapa de variables desde el fichero,
deduciendo si la variable pertenece al apb o al regifle a partir del
prefijo del nombre (P_ y v_ para el regfile, in_ y out_ para el apb).
MEMORIA. SIMULADOR 35
7.2.2 LoadOuts
Figura 21. Función LoadOuts.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Carga los nombres de las salidas correspondientes a
cada tarea. No se hace al inicio para que si no existe el fichero no de
error al iniciar el programa, sino solo si se quiere comprobar la
simulación de VHDL, ya que para lo demás no es necesario.
7.2.3 SaveVar
Figura 22. Función SaveVar.
• Argumentos de entrada: Nombre y valor de la variable a guardar y
tarea en ejecución.
MEMORIA. SIMULADOR 36
• Argumentos de salida: Ninguno.
• Función principal: Guarda la información de la variable leída en el
lugar que corresponda.
• Funcionamiento:
1. Tras comprobar que la variable está en el mapa, busca en task_outs si
es una salida de la tarea en ejecución, si es así, lo guarda en el propio
vector task_outs.
2. Si no es una salida de la tarea en ejecución, será una entrada. Así
que la guarda en el apb o en el regfile.
7.2.4 CheckOutputs
Figura 23. Función CheckOutputs.
• Argumentos de entrada: Tarea en ejecución.
• Argumentos de salida: Ninguno.
• Función principal: Comprueba diferencias entre los valores del las
variables del vector task_outs correspondientes a la tarea en ejecución, y
sus valores en el regfile y el apb, si el error es mayor que la tolerancia,
muestra un mensaje de error.
MEMORIA. SIMULADOR 37
8 Clase sys
Figura 24. Elementos de la clase sys.
En la clase sys se engloban todos los elementos que simulan un DSP, se
puede entender como la parte más hardware del programa, de modo que
creando el objeto sys ya se tiene un DSP con todas sus funciones.
Conseguimos así una gran analogía entre la estructuración del elemento a
simular y la del programa simulador.
8.1 Funciones
8.1.1 Init
Figura 25. Función Init.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
MEMORIA. SIMULADOR 38
• Función principal: Inicializa todos los objetos del sistema.
8.1.2 Step
Figura 26. Función Step.
• Argumentos de entrada: Ninguno ó tarea a ejecutar.
• Argumentos de salida: bool con valor 1 si el dsp ha llegado al final de la
tarea.
• Función principal: Ejecuta una instrucción de programa de la tarea
ordenada por el Task Manager, también se puede forzar una tarea en
concreto, esta funcionalidad se usa en el modo de comprobación de
simulación VHDL.
• Funcionamiento:
1. Lee del dsp los ciclos de reloj
2. Se los indica al Task Manager, que le devuelve la tarea a ejecutar.
3. Si el Task Manager indica que hay que cambiar de tarea, le dice al
dsp que cargue el contexto de la nueva tarea.
4. Indica al dsp que decodifique y ejecute una instrucción
5. Actualiza el apb
6. Devuelve 1 si el dsp ha ejecutado la instrucción halt, que indicaría
que se ha llegado al final de la tarea.
MEMORIA. SIMULADOR 39
9 Clase sim
Figura 27. Elementos principales de la clase sim.
La clase sim es el simulador completo, contiene al sistema (objeto de la
clase sys) junto con funciones para actuar sobre él u obtener información y
al objeto var, donde se almacenan y se procesan las variables necesarias
para la comprobación de la simulación de ModelSim.
Se dejan sin embargo fuera de esta clase las funciones necesarias para que
el usuario se comunique con el simulador, ya que estas dependen de la
forma en la que el usuario introduzca los comandos, que puede ser por
teclado directamente, a través de la Interfaz Gráfica, o mediante ficheros
de entrada.
La clase sim es por tanto ajena al método usado para pedirle la
información, pues todo es traducido a comandos fáciles de interpretar
antes de comunicarse con ella. Es la encargada de manejar el simulador en
base a la configuración introducida y las peticiones hechas, que son leídas
por su función más importante, Execute.
9.1 Datos principales
• break_pc, que es un set de puntos de ruptura del programa (breakpoints).
Poner un breakpoint en cualquier punto de la memoria del programa
conlleva que al intentar ejecutar la tarea completa, se para en el punto
MEMORIA. SIMULADOR 40
indicado, para luego seguir sólo si se le indica. Facilita mucho estudiar
una parte concreta del código rápidamente.
9.2 Funciones principales
9.2.1 Init
Figura 28. Función Init.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Inicializa el sistema y el objeto con la información
de las variables y borra los breakpoints.
MEMORIA. SIMULADOR 41
9.2.2 LoadConfig
Figura 29. Función LoadConfig.
• Argumentos de entrada: Nombre del archivo de configuración.
• Argumentos de salida: bool con valor 1 si ha habido algún error, y cero
si no.
• Función principal: Carga la configuración del sistema desde el archivo
externo.
9.2.3 Execute
Figura 30. Función Execute.
• Argumentos de entrada: Un vector con las palabras que forman el
comando pedido y un bool que indica si se está trabajando por medio
MEMORIA. SIMULADOR 42
de tuberías con la Interfaz Gráfica, en cuyo caso la información se
presenta más simplificada. En el Parte ICapítulo 42.2 se explica más a
fondo la comunicación entre el simulador y la interfaz gráfica.
• Argumentos de salida: Ninguno.
• Función principal: Interpreta los comandos pedidos y utiliza las
funciones internas que les corresponden.
9.2.4 Disassemble
Figura 31. Función Disassemble.
La función está sobrecargada, por lo que tiene dos tipos de
funcionamientos dependiendo del tipo de valores de entrada. Si se usa un
argumento de entrada int:
• Argumentos de entrada: Dirección de la memoria ROM a
desensamblar y un bool que indica si se ha de imprimir por pantalla el
resultado o sólo devolverlo.
• Argumentos de salida: string con la instrucción desensamblada
• Función principal: Permite obtener la línea de ensamblador con la que
fue codificada cada instrucción de la memoria.
Y si la entrada es de tipo string:
• Argumento de entrada: Nombre del fichero a crear
MEMORIA. SIMULADOR 43
• Argumentos de salida: Ninguno.
• Función principal: Crea un fichero externo con las instrucciones de
toda la memoria ROM desensambladas en el orden en que están en
memoria.
9.2.5 CheckVHDL
Figura 32. Función CheckVHDL.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Comprueba la simulación del programa con la
realizada por el programa de simulación de VHDL ModelSim.
• Funcionamiento: Esta funcionalidad del simulador se entiende mejor
con un ejemplo. Esta es una parte extraída del fichero que genera
ModelSim con su simulación:
…
Executing task number 1
2128688965 ps in_motor_current_id 5725
2128933115 ps in_motor_current_iq -315
2131618765 ps in_dc_link 1
2131814085 ps in_ema_position 1
2133913775 ps v_rate_command 0.000000e+00
2134157925 ps v_id_order 0.000000e+00
2135622825 ps v_motor_speed 0.000000e+00
2136843575 ps v_vd_order -1.143601e+02
MEMORIA. SIMULADOR 44
2137136555 ps v_current_order 0.000000e+00
2140115185 ps v_vq_order 6.292301e+00
Executing task number 5
…
Y a nuestro simulador le hemos indicado que las variables que se
consideran salidas de la tarea 1 son v_vd_order y v_vq_order.
El funcionamiento sería el siguiente:
1. Lee la tarea que se ejecuta (1).
2. Guarda las variables que no son salidas de la tarea en el regfile
(v_rate_command, v_id_order, v_motor_speed y v_current_order), o en el
apb (in_motor_current_id, in_motor_current_iq, in_dc_link e
in_ema_position), y las que son salida (v_vd_order y v_vq_order) en
una lista especial.
3. Ejecuta la tarea entera (la tarea 1) en el sistema sys.
4. Compara los valores de las variables de salida guardadas y las
obtenidas por simulación (v_vd_order y v_vq_order en regfile y
v_vd_order y v_vq_order guardadas en la el objeto variables).
5. Si la diferencia es mayor que la tolerancia, saca un error por
pantalla.
9.2.6 AllTask
Figura 33. Función AllTask.
MEMORIA. SIMULADOR 45
• Argumentos de entrada: Ninguno, o bien la tarea concreta a ejecutar,
si se quiere forzar un cambio de tarea (para usarlo con CheckVHDL).
• Argumentos de salida: Ninguno.
• Función principal: Ejecuta instrucciones de la memoria ROM hasta que
termine la tarea, o hasta encontrar un punto de ruptura.
9.2.7 AddBreakpoint, DeleteBreakPoint y DeleteAllBreakpoints
Figura 34. Funciones de manejo de breakpoints.
Simplemente mencionar que al añadir un punto de ruptura, se guarda en
el set break_pc la dirección del breakpoint. Y luego es la función AllTask la
que se preocupa en cada instrucción de comparar la dirección de la
instrucción a ejecutar con el conjunto de breakpoints.
MEMORIA. SIMULADOR 46
9.2.8 LoadState y SaveState
Figura 35. Funciones LoadState y SaveState.
Guardando el estado completo de la simulación y pudiendo cargarlo
luego, podemos partir la simulación, osea no tener que hacerlo todo
seguido. Es algo que puede ser muy útil en simulaciones extremadamente
largas.
9.2.9 CheckString
Figura 36. Función CheckString.
• Argumentos de entrada: String esperada, string leída y stream de
entrada.
• Argumentos de salida: bool con valor 1 si ocurre algún error.
MEMORIA. SIMULADOR 47
• Función principal: En lecturas de ficheros grandes, como el de
configuración y el de estado, permite dar un error más específico. Se
llama a la función varias veces en la lectura del fichero, y solamente se
sigue leyendo esta función no devuelve error. También se encarga de
ignorar los comentarios.
9.2.10 Get… y Print…
Figura 37. Funciones Get… y Print….
Tan sólo mencionar que se han incorporado unas funciones para obtener y
para sacar por pantalla fácilmente los datos principales del sistema. Estas
no sólo sirven para simplificar el resto de las funciones del simulador, sino
también facilitan las posibles ampliaciones que se realicen.
10 Comunicación del simulador
El simulador se puede comunicar de cuatro maneras distintas, que son:
MEMORIA. SIMULADOR 48
10.1 Modo interactivo normal
Figura 38. Comunicación modo interactivo.
Llamando al simulador a través de una ventana de comandos con un
archivo de configuración se abre el programa, que llama a la función
RunInteractive presentando un menú como del de la Figura 38, en el que
espera la introducción de comandos por parte del usuario, y se muestran
los resultados en la misma ventana.
Un ejemplo de comando usado para llamar al programa podría ser:
>dsp_sim.exe –c config.dspp
10.2 Modo entrada por fichero, salida por ventana
Otra posibilidad es escribir en un fichero los comandos que se quiera que
el simulador ejecute, para automatizar las pruebas. Un ejemplo de fichero
de entrada:
run task
MEMORIA. SIMULADOR 49
run step3
print apb 14
run task
print regfile 4
run step 5
Luego se llama al programa con un comando como:
>dsp_sim.exe –c config.dspp –i InputCmd.txt
El programa lee los comandos del fichero y presenta los resultados por
pantalla.
Figura 39. Modo entrada por fichero, salida por ventana.
Los resultados se presentan como se puede ver en la Figura 39, del mismo
modo que en el modo interactivo normal.
10.3 Modo entrada por fichero, salida por fichero
Es prácticamente igual que el modo anterior, pero los resultados se dejan
en el fichero de salida indicado. Un ejemplo de comando podría ser:
>dsp_sim.exe –c config.dspp –i InputCmd.txt –o Output.txt
10.4 Modo interactivo por tuberías con la Interfaz Gráfica
El funcionamiento de las tuberías se explica más a fondo en la parte de la
interfaz gráfica. Por parte del simulador, el modo es igual que el
interactivo normal en cuanto a la lectura de comandos, y prácticamente
MEMORIA. SIMULADOR 50
igual en la presentación de resultados, la única diferencia es que muchos
datos se presentan de manera más sencilla de extraer por parte de la
Interfaz, por ejemplo:
print regfile 4
En el modo interactivo normal da lugar a:
Dir = 4, Value in hex = 41921f, Value in float = 6.28314
Mientras que en éste modo se simplifica a:
DIR 4 41921f 6.28314
El comando con el que se puede llamar al simulador en este modo es:
>dsp_sim.exe –c config.dspp –p
11 Estructura del main
Para terminar de presentar el programa, se enumeran los pasos que se
siguen en el fichero principal del programa.
1. Se crea un objeto de la clase simulador.
2. Se averigua el método de comunicación a usar en base a los
argumentos con los que se ha llamado al programa.
3. Si el método de comunicación es de salida a fichero, se redirecciona
ya hacia el fichero, para que posibles errores aparezcan en él.
4. Configura el simulador y lo inicializa.
5. Dependiendo del método de comunicación, elige la función
adecuada, pasándole la dirección del objeto sim.
MEMORIA. INTERFAZ GRÁFICA 51
Capítulo 4 INTERFAZ GRÁFICA
1 Introducción
1.1 Para qué una interfaz gráfica
Se puede deducir leyendo el Capítulo 2, Ensamblador y el Capítulo 3,
Simulador que todos los objetivos que tenía que cumplir el entorno de
desarrollo ya están cubiertos, pues ya hemos creado los programas
necesarios para poder ensamblar nuestro código de programa, y simular
su comportamiento en un DSP virtual. Entonces, ¿Para qué queremos un
Interfaz gráfica? Principalmente por los siguientes dos motivos:
• La interfaz gráfica entre en usuario y el programa reduce en gran
medida el tiempo que un nuevo usuario tiene que invertir para
aprender a usar en entorno de desarrollo, pues tanto las funciones que
quiere ejecutar como los datos que quiere obtener se presentan de
manera mucho más intuitiva.
• Ahorra tiempo para el usuario que también sabría usar el simulador en
modo consola, pues siempre se tienen a la vista los datos principales de
la simulación, mientras que en el modo consola hay que pedirlos
expresamente.
En definitiva, la interfaz gráfica no añade funcionalidades al entorno de
desarrollo, sino que su único objetivo es simplificar y agilizar su uso.
1.2 wxWidgets
Para el desarrollo de interfaz se ha elegido la herramienta wxWidgets,
específicamente diseñada para el desarrollo de este tipo de programas.
MEMORIA. INTERFAZ GRÁFICA 52
Las principales ventajas que nos ofrece son: ser de código abierto, gratuita,
muy sencilla y muy potente, y poder generar código absolutamente
portable a los sistemas operativos principales (Linux, Windows y Mac). En
el apartado [6] de la bibliografía se indica la página web desde la cual se
puede descargar.
WxWidgets incluye una biblioteca de funciones con las cuales se puede
generar la interfaz al completo, pero también se puede descargar un
“plugin” para la herramienta Codeblocks, que es la que se está usando
como IDE, que facilita mucho el desarrollo al permitir organizar las
ventanas, botones y demás ítems de manera gráfica. En la referencia [7] de
la bibliografía se facilita una página web en la que se explica como
descargar e instalar el “plugin”.
Para aquel que quiera usar ésta herramienta, es recomendable hacer un
par de tutoriales:
1. Uno muy básico sobre el uso de wxWidgets junto con CodeBlocks para
desarrollar herramientas de manera gráfica. Un enlace a la página se
encuentra en la referencia [8].
2. Un tutorial sobre el uso de las funciones de wxWidgets, ya que la
mayoría de la programación se tendrá que hacer “a mano” usando
éstas funciones. El enlace puede ver en la referencia [9].
2 Comunicación con los programas. Clase Console
Figura 40. Comunicaciones entre programas.
MEMORIA. INTERFAZ GRÁFICA 53
Como se puede ver en la Figura 40, la interfaz gráfica se ha de comunicar
con los dos programas ya comentados. Aunque esta comunicación se lleva
a cabo de manera distinta para un programa y para otro, se ha creado una
clase en la que se engloba todas las funciones necesarias.
Figura 41. Elementos principales de la clase console.
Pero antes de explicar los datos y funciones de ésta clase, se va a comentar
brevemente los métodos de comunicación.
2.1 Comunicación con el ensamblador
El proceso de ensamblar el código del programa es algo puntual, por lo
tanto la interfaz solamente llama al programa ensamblador con los
argumentos adecuados, y recoge la salida. Para ello se usa la función
wxExecute, que ejecuta lo que se le indica como si fuera una ventana de
comandos, se le pasan como argumentos dos vectores donde guarda la
salida que el programa daría por pantalla, que luego se muestra en el
panel de mensajes.
2.2 Comunicación con el simulador
La comunicación con el simulador es un poco más compleja, pues la
interfaz necesita estar continuamente haciendo peticiones y recogiendo la
información que se le devuelve.
MEMORIA. INTERFAZ GRÁFICA 54
Existe algo especialmente diseñado para éste tipo de comunicaciones, las
tuberías (a veces se le llama directamente en inglés, pipes), éstas son un
método por el cual se puede mandar información desde un proceso del
sistema a otro, y se deja en manos del sistema operativo el llevar la
información. En la referencia [10] se cita una página web donde se explica
más a fondo el funcionamiento de las tuberías.
Puesto que el sistema operativo del ordenador está tan implicado en el uso
de las tuberías, se definen y se usan de manera ligeramente distinta
dependiendo del S.O. con el que trabajemos. Por suerte, wxWidgets tiene
sus propias funciones para la creación y el uso de tuberías, que
simplemente llaman a las funciones específicas que haya que usar
dependiendo del sistema que usemos, esto nos permite seguir trabajando
con código perfectamente portable.
2.3 Datos principales de la clase console
• Una estructura en la que se han englobado los datos principales del
estado del microprocesador, ps:
o Valor del contador del programa, PC.
o Número de ciclos de reloj, clk_tick.
o Tarea en ejecución, current_task.
o Bandera para instrucciones condicionales, flag.
o Una bandera que indica si ha habido algún error en la palabra de
status, status_fail.
o La palabra de status en sí, status.
o Contexto de la tarea almacenado en el dsp, dsp_tc, que a su vez
contiene el PC de cada tarea y el PC_reset, que indica a que dirección
debe ir la tarea al empezar de nuevo
MEMORIA. INTERFAZ GRÁFICA 55
o Contexto de cada tarea almacenado en el Task Manager. Para cada
tarea se tiene:
� priority, la prioridad de la tarea.
� active, que indica que la tarea no está deshabilitada.
� period, el periodo con el que se ha de ejecutar la tarea.
� state, el estado de la tarea (ejecutándose, esperando o parada).
� ready_tick, el ciclo de reloj en el que se ha de despertar la tarea.
• Un puntero a un objeto de la clase wxProcess, con la información
necesaria para manejar el proceso del simulador.
• Tres punteros a los canales por los que se manda información (p_os), se
recibe información normal (p_is) y se reciben errores (p_es).
2.4 Funciones principales de la clase console
2.4.1 Assemble
Figura 42. Función Assemble.
• Argumentos de entrada: Nombre del archivo a ensamblar.
MEMORIA. INTERFAZ GRÁFICA 56
• Argumentos de salida: 1 si se produce algún error en el proceso, 0 si
no.
• Función principal: Llama al programa ensamblador y recoge la
información devuelta.
• Funcionamiento:
1. Lee de la clase f_names los nombres que se les quiere dar a los
archivos que se van a generar al ensamblar, y si se van a codificar
los registros en 24 o en 32 bits.
2. Se llama al ensamblador a través de la función wxExecute,
pidiéndole que guarde en unos vectores de strings la respuesta que
da el programa.
3. Se muestra por pantalla esta información usando llamando a la
función ShowErrorsAndWarnings.
4. Si no hay errores, se llama a la función declarada como global
SetAsmFinished, para la información de otros paneles y se abre la
comunicación con el simulador.
5. También solo si no se han producido errores, se actualiza el panel
con los registros y el APB y se carga el “backannotation file” en el
panel del programa.
MEMORIA. INTERFAZ GRÁFICA 57
2.4.2 OpenProcess
Figura 43. Función OpenProcess.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Abre en proceso de comunicación con el simulador
y monta los canales (“streams”) de envío y recepción de datos (p_is,
p_os y p_es).
MEMORIA. INTERFAZ GRÁFICA 58
2.4.3 KillProcess
Figura 44. Función KillProcess.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Cierra el proceso del simulador a través de función
wxProcess::Kill y comprueba que se haya cerrado correctamente.
MEMORIA. INTERFAZ GRÁFICA 59
2.4.4 Execute
Figura 45. Función Execute.
• Argumentos de entrada: El comando, y dos bool, uno indica si se ha de
imprimir en el panel de mensajes lo actualizado y otro si se han de
actualizar los paneles.
• Argumentos de salida: 1 si ha ocurrido algún error, 0 si no.
• Función principal: Ejecuta el comando indicado en el simulador y
actualiza los paneles con la información devuelta.
• Funcionamiento:
1. Comprueba que se haya ensamblado el proyecto, de no ser así no
sigue adelante.
2. Escribe el comando en p_os seguido de un retorno de carro.
3. Si así se ha indicado, escribe en el panel de mensajes el comando
escrito.
4. Espera a que haya algo como salida del proceso simulalor, p.
5. Lee la salida del proceso a través del canal p_is.
MEMORIA. INTERFAZ GRÁFICA 60
6. Si se ha pedido, actualiza los paneles de toda la interfaz con la
función UpdatePanels.
2.4.5 GetAndUpdateState
Figura 46. Función GetAndUpdateState.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: 1 si ha ocurrido algún error, 0 si no.
• Función principal: El comando print state en el simulador, y leyendo la
información devuelta y comprobando con la función CheckString
actualiza la estructura en la que se guarda el estado del simulador, ps.
MEMORIA. INTERFAZ GRÁFICA 61
2.4.6 UpdatePanels
Figura 47. Función UpdatePanels.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: 1 si ha ocurrido algún error, 0 si no.
• Función principal: Actualiza los paneles de la interfaz a partir de la
información del simulador almacenada en ps.
MEMORIA. INTERFAZ GRÁFICA 62
2.4.7 CheckString
Figura 48. Función CheckString.
• Argumentos de entrada: wxString esperada, wxString leída y stream de
entrada.
• Argumentos de salida: bool con valor 1 si ocurre algún error.
• Función principal: Igual que la función implementada en el simulador,
aunque trabaja con tipos de datos algo distintos, en lecturas de muchos
datos, como al actualizar el estado, permite dar un error más
específico. Se llama a la función varias veces en la lectura del fichero, y
solamente se sigue leyendo si esta función no devuelve error. También
se encarga de ignorar los comentarios.
MEMORIA. INTERFAZ GRÁFICA 63
3 Diálogo de configuración
Figura 49. Diálogo de Configuración.
Al abrir un proyecto o al crear uno nuevo se muestra su configuración,
como se aprecia el la Figura 49 para poder modificarla fácilmente. En
cuatro pestañas se indican:
• Opciones globales del simulador, como si los registros trabajan en 24 o
en 32 bits, los tamaños de las memorias, y los nombres de los ficheros
que maneja el programa.
• Las tareas implicadas en el programa, con sus prioridades y sus
periodos.
MEMORIA. INTERFAZ GRÁFICA 64
• Los esclavos del APB, con su tipo, su nombre y su posición en la
memoria del APB.
• El archivo con el programa en ensamblador. Si se indica un fichero que
no existe, se crea en blanco.
Tras configurar todas estas opciones, la interfaz genera un fichero de
configuración como el que se puede ver en los anexos, Capítulo 54.1, y al
abrir el proyecto de nuevo simplemente carga la configuración en el
diálogo a partir del fichero.
3.1 Estructuración en el programa
3.1.1 Separación del diálogo y el panel
Figura 50. Separación entre el diálogo y el panel de configuración.
Por seguir una estructura homogénea en cuanto al método de
programación de la interfaz en wxWidgets, se ha implementado el diálogo
de configuración como un panel dentro de un diálogo, y no simplemente
como un diálogo, como se puede ver en la Figura 50. De este modo toda la
interfaz al completo son simplemente paneles, y se podría reorganizar
MEMORIA. INTERFAZ GRÁFICA 65
para meter el panel de configuración dentro de la ventana principal del
programa si así se quisiera.
Esta estructuración se ve reflejada en los ficheros de las fuentes del
programa, se ha creado un fichero “configure_dialog” con su clase
configure_dialog dentro, que crean en su interior un objeto de la clase
confugure_panel que se implementa en los ficheros “configure_panel”. De
querer por tanto colocar la configuración de otra manera habría que
instanciar el panel, pudiendo eliminar el diálogo.
3.1.2 Clase project
Se ha separado de las clases en las que se obtiene la configuración esta
clase, en la que se guarda toda la información relativa al proyecto abierto
en la interfaz. Aunque tiene valores por defecto, cuando se completa el
diálogo de configuración se crea un objeto de esta clase, con los nombres
de los archivos, la carpeta de proyecto y demás. Se deja así fácil crear una
ampliación en la que se puedan tener más de un proyecto abierto. Aunque
habría que cambiar más cosas en el aspecto gráfico, aquí simplemente
habría que crear más objetos de la clase project.
No se comentan sus funciones puesto que son muy básicas, tan sólo
mencionar que existen las siguientes:
• SetProjectLoaded, IsProjectLoaded.
• SetAsmFinished, IsAsmFinished.
• SetProjectSaved, IsProjectSaved.
• SetProjectPath, GetProjectPath.
MEMORIA. INTERFAZ GRÁFICA 66
3.2 Clase configure_panel
Figura 51. Elementos principales de la clase configure_panel.
La clase configure_panel se deriva de la clase wxPanel, estandar de
wxWidgets. Comprende toda la distribución de la parte gráfica del panel,
es decir, botones, cuadros de texto, listas, etc. y además una serie de
funciones para manejar la configuración del proyecto. Se explican primero
las funciones grandes, donde se concentra la mayor parte del código, y
más adelante muy brevemente el conjunto de funciones que sirven para el
manejo de eventos, como por ejemplo apretar un botón.
3.2.1 Datos principales de la clase configure_panel
• En los paneles está toda la información importante, de modo que tener
el dato del nombre de un fichero, por ejemplo, se puede leer
directamente del lugar donde el usuario introduce el texto.
• tasks es un vector donde se almacenan las tareas y las características de
éstas que se introducen. Al ser un dato algo más complejo, se guarda
en un vector aparte, para facilitar su manejo por las distintas funciones.
• slaves es un vector donde se almacena la información relativa a los
esclavos, por razones idénticas a tasks.
3.2.2 Funciones principales de la clase configure_panel
3.2.2.1 Apply
MEMORIA. INTERFAZ GRÁFICA 67
Figura 52. Función Apply
• Argumentos de entrada: Ninguno.
• Argumentos de salida: 1 si se produce algún error en el proceso, 0 si
no.
• Función principal: Guarda en la clase project toda la información
contenida en el diálogo de configuración si la función Check le dice que
es correcta.
3.2.2.2 SaveFile
Figura 53. Función SaveFile
• Argumentos de entrada: Nombre del archivo en el que se ha de
guardar.
• Argumentos de salida: 1 si se produce algún error en el proceso, 0 si
no.
MEMORIA. INTERFAZ GRÁFICA 68
• Función principal: Guarda en un fichero externo (archivo de proyecto)
toda la información contenida en el diálogo de configuración tras
comprobar con la función Check.
3.2.2.3 LoadFile
Figura 54. Función LoadFile.
• Argumentos de entrada: Nombre del archivo que se quiere cargar.
• Argumentos de salida: 1 si se produce algún error en el proceso, 0 si
no.
• Función principal: Carga de un fichero externo (archivo de proyecto)
toda la información sobre el proyecto al diálogo de configuración, para
ello usa la función ya comentada en 2.4.7 CheckString, y otra muy
básica, ReadIgnoringComments.
3.2.2.4 Check
Figura 55. Función Check
• Argumentos de entrada: Ninguno.
MEMORIA. INTERFAZ GRÁFICA 69
• Argumentos de salida: 1 si se produce algún error en el proceso, 0 si
no.
• Función principal: Comprueba que ningún campo esté vacío y que
tengan nombres válidos, es decir, que los nombres no tengan espacios.
3.2.3 Funciones de manejo de eventos de la clase configure_panel
A parte de las funciones ya explicadas, se han tenido que implementar
algunas funciones auxiliares para que se ejecuten cuando ocurre un
evento. Se mencionan a continuación sobre las diferentes pestañas.
3.2.3.1 Opciones globales
Figura 56. Pestaña de opciones globales del panel de configuración.
Como se pude ver, esta pestaña es muy sencilla, por lo que no se ha tenido
que crear ninguna función para ningún evento.
3.2.3.2 Tareas
MEMORIA. INTERFAZ GRÁFICA 70
Figura 57. Pestaña de tareas del panel de configuración.
Se han creado las siguientes funciones de manejo de eventos:
1. OnListTaskSelect, que se ocupa de cargar el periodo de la tarea y si
está activa o no en la zona de abajo del panel cuando se elige una
tarea nueva.
2. OnTaskAddButtonClick, que añade una tarea a la lista de la zona
superior derecha del panel y añade un elemento al vector interno de
tareas, tasks.
3. OnTaskDeleteButtonClick, que borra la tarea seleccionada de la lista
de la zona superior derecha del panel y del vector interno de tareas,
tasks.
4. OnTaskUpButtonClick y OnTaskDownButtonClick se ocupan de los
botones que permiten reordenar las tareas en la lista y en el vector
interno. El orden de las tareas determina su prioridad, siendo la
tarea de mayor prioridad la posicionada en la parte superior de la
tabla.
MEMORIA. INTERFAZ GRÁFICA 71
5. OnTaskPeriodHexChange y OnTaskPeriodDecChange se encargan de
que cuando se cambie el valor del periodo en uno de los paneles se
guarde el periodo en el vector tasks.
6. OnTaskActiveCheckboxClick guarda el estado de la tarea en el vector
tasks.
3.2.3.3 Esclavos de APB
Figura 58. Pestaña de esclavos del panel de configuración.
1. OnListSlavesSelect carga en el resto de la pestaña la información
relativa al esclavo que se selecciona.
2. OnSlaveAddButtonClick añade un esclavo a la lista y un elemento al
vector slaves, donde se guarda la información sobre los esclavos.
3. OnSlaveDeleteButtonClick borra el esclavo seleccionado de la lista del
panel y del vector slaves.
MEMORIA. INTERFAZ GRÁFICA 72
4. OnSlaveUpButtonClick y OnSlaveDownButtonClick reorganizan los
esclavos en la lista del panel y del vector, esto no tiene ninguna
utilidad aparte de organizarlos como uno quiera.
5. OnSlaveNameTextChange cambia el nombre del esclavo en el vector y
en la lista del panel según se cambia en el cuadro de texto.
6. OnSlaveTypeChoiceSelect cambia el tipo de esclavo dentro del vector
y esconde o enseña el apartado del panel en el que se puede indicar
si el esclavo es sólo de entrada, sólo de salida, o de entrada y salida,
disponible únicamente para esclavos de tipo secuencial.
7. OnSlaveMemoryStartTextChange y OnSlaveMemoryEndTextChange
guardan en el vector los valores de comienzo y fin de la memoria
según los escribe el usuario.
8. OnSlaveInputFileTextChange y OnSlaveOutputFileTextChange Guardan
en el vector slaves los nombres de los archivos de entrada y salida
del esclavo.
9. OnSlaveSeqRadioSelect sirve para guardar en el vector slaves el tipo
de esclavo secuencial. Si el esclavo no es de tipo secuencial no se
puede seleccionar, al estar desactivado.
3.2.3.4 Archivo de ensamblador
MEMORIA. INTERFAZ GRÁFICA 73
Figura 59. Pestaña de Archivo ensamblador del panel de configuración
Simplemente se ha añadido un función:
1. OnAsmOpenButtonClick abre un diálogo estandar de selección de
archivo, y si se devuelve el nombre de un archivo que no existe, crea
uno en blanco.
MEMORIA. INTERFAZ GRÁFICA 74
4 Panel del procesador
Figura 60. Panel del procesador.
En la Figura 60 se puede observar el panel de procesador de la interfaz
gráfica, en él se muestra la información básica para conocer el estado del
DSP. Este panel se ha implementado con una clase derivada de la clase
wxPanel, que ha sido nombrada processor_panel.
Figura 61. Elementos principales de la clase processor_panel.
La clase processor_panel contiene los mínimos datos posibles, simplemente
elementos gráficos, y luego tiene una serie de funciones para manejar su
MEMORIA. INTERFAZ GRÁFICA 75
apariencia y para obtener los datos de archivos o de la clase console, como
se explica posteriormente, y presentarlos en el panel.
4.1 Datos principales
• Tabla ROM, se ha implementado con la clase wxGrid, en ella se muestra
la memoria ROM, tanto sus valores en hexadecimal como cada
instrucción desensamblada. Subrayada en verde está la instrucción
actual del DSP, y en con letras en rojo aparecen los puntos de ruptura
(“breakpoints”).
• Tabla de las tareas, aquí se puede ver el estado de las tareas en todo
momento.
• Program Counter, tanto en decimal como en hexadecimal.
• Reloj del sistema, Clk, también en decimal y en hexadecimal.
• Flag del sistema, la bandera que se usa para instrucciones
condicionales.
• Status word, la palabra de status que se recibe desde el exterior del DSP.
4.2 Funciones principales
4.2.1 Load
Figura 62. Función Load.
• Argumentos de entrada: Ninguno.
MEMORIA. INTERFAZ GRÁFICA 76
• Argumentos de salida: Ninguno.
• Función principal: Lee de proyect los archivos del proyecto, y carga la
tabla de tareas y la de ROM, para lo cual tiene que llamar a la función
Disassemble.
4.2.2 Disassemble
Figura 63. Función Disassemble.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Lee de proyect los archivos del proyecto, pide a
console que mande al simulador crear un archivo de desensamblado, y
lo carga a la tabla ROM.
4.2.3 Update
Figura 64. Función Update.
MEMORIA. INTERFAZ GRÁFICA 77
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Lee el dato ps de console, que contiene toda la
información sobre en estado del procesador, y la carga en los distintos
elementos del panel.
4.2.4 Breakpoints
Figura 65. Funciones de breakpoints.
• Argumentos de entrada: AddBreakpoint y DelBreakpoint necesitan como
entrada la dirección de la memoria en la que añadir o borrar un
“breakpoint”.
• Argumentos de salida: Ninguno.
• Función principal: Cambia simplemente el color de la tabla ROM para
indicar que hay un punto de ruptura o no.
MEMORIA. INTERFAZ GRÁFICA 78
5 Panel del programa
Figura 66. Panel del programa.
Como se puede ver en la Figura 66, el panel del programa es bastante
simple, está implementado como un wxNotebook con dos pestañas, en la
primera se carga el código en ensamblador y en la segunda tras ensamblar
se carga automáticamente el fichero “backannotation”, en el que podemos
ver el código escrito junto con el código que se ensambla, además se
subraya en verde la instrucción que se está ejecutando en la simulación.
Figura 67. Elementos principales de la clase program_panel.
Se ha implementado el panel con una clase derivada de wxPanel, que se ha
nombrado program_panel, cuyos elementos principales se pueden observar
en la Figura 67.
MEMORIA. INTERFAZ GRÁFICA 79
5.1 Datos principales
• program_text es el elemento de la clase wxRichTextCtrl en el que se
carga el código de ensamblador. Sobre él se puede crear y modificar el
código como cualquier editor de texto básico.
• Backannotation_text es otro elemento de la clase wxRichTextCtrl. Es de
sólo lectura, por lo que simplemente sirve para comprobar el programa
ensamblado y seguir su ejecución sobre el código.
5.2 Funciones principales
5.2.1 LoadBA
Figura 68. Función LoadBA.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Accede al objeto proyect para mirar el nombre del
archivo a cargar, lo carga en el elemento backannotation_text y cambia
de pestaña para mostrarlo.
MEMORIA. INTERFAZ GRÁFICA 80
5.2.2 Update
Figura 69. Función Update.
• Argumentos de entrada: Contador de programa de la simulación (PC).
• Argumentos de salida: Ninguno.
• Función principal: Busca en el backannotation_text la línea de código
correspondiente al PC actual, la subraya y la muestra
5.2.3 ShowError
Figura 70. Función ShowError.
• Argumentos de entrada: Número de línea del error.
• Argumentos de salida: Ninguno.
• Función principal: Busca en el program_text la línea de código que tiene
un error que impide el ensamblado, la subraya y la muestra.
MEMORIA. INTERFAZ GRÁFICA 81
5.2.4 ClearUnderline
Figura 71. Función ClearUnderline.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: “Limpia” el backannotation_text de líneas
subrayadas.
6 Panel de registros
Figura 72. Panel de registros.
El panel de registros cuenta con tres pestañas, en cada una de las cuales se
puede ver la variable, su dirección en memoria y su valor tanto en
hexadecimal como en coma flotante, como se puede ver en la Figura 72, se
marca de color azul la variable que ha cambiado de valor en la última
instrucción ejecutada. Las tres pestañas son:
MEMORIA. INTERFAZ GRÁFICA 82
• Registers, donde están las variables internas del microprocesador.
• APB, donde se encuentran las variables tanto de entrada como de
salida del APB.
• Watched, donde el usuario elige que variables quiere ver y en que
orden, tanto de los registros como del APB, para poder controlar más
cómodamente las que interesen.
Figura 73. Elementos principales de la clase registers_panel.
En la Figura 73 se pueden ver los elementos principales de la clase
registers_panel, derivada como todos los paneles de wxPanel.
6.1 Datos principales
• Dos vectores de estructuras de datos (reg_info y apb_info) tienen toda la
información que el panel necesita sobre cada elemento de los registros
o del APB, los datos de la estructura son los siguientes:
o name, el nombre de la constante o variable.
o dir, su dirección en memoria.
o value, su valor en hexadecimal.
o value_f, su valor en coma flotante.
o row, la fila en la que está representada la constante o variable en las
tablas del panel.
MEMORIA. INTERFAZ GRÁFICA 83
o used, un valor con el que se marca al inicializar el vector las
direcciones que se usan, puesto que el vector tiene el tamaño de la
memoria, y no toda ella se usa.
o watched, que indica que el usuario ha puesto también el elemento en
la tabla de variables watch.
o watched_row, para indicar en que fila de la tabla de variables a
controlar se ha situado.
o changed, que indica que el valor de la variable ha cambiado desde la
última instrucción, para saber que se debe marcar.
• Las tres tablas, que son objetos de la clase wxGrid
6.2 Funciones principales
6.2.1 Init
Figura 74. Función Init.
• Argumentos de entrada: Nombres de los archivos a cargar y tamaños
de las memorias de registros y del APB.
• Argumentos de salida: Ninguno.
• Función principal: Carga los valores iniciales de los registros y el mapa
de variables tanto en los vectores internos reg_info y apb_info como en
las tablas de los paneles.
MEMORIA. INTERFAZ GRÁFICA 84
6.2.2 Update
Figura 75. Función Update.
• Argumentos de entrada: El vector de strings que devuelve el simulador
al objeto console cuando ejecuta “print regfile” y “print apb”.
• Argumentos de salida: Ninguno.
• Función principal: Almacena los valores actualizados de los registros y
el APB en los vectores reg_info y apb_info.
6.2.3 Refresh
Figura 76. Función Refresh.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Actualiza las tablas del panel con la información de
los vectores.
MEMORIA. INTERFAZ GRÁFICA 85
6.2.4 Watch y Clear
Figura 77. Funciones Watch y Clear.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Manda la variable a la pestaña watch o la borra de él,
modificando acordemente los vectores reg_info y apb_info.
6.2.5 Up y Down
Figura 78. Funciones Up y Down.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Cambia de lugar los elementos de la tabla watch,
almacenando los cambios en los vectores reg_info y apb_info.
MEMORIA. INTERFAZ GRÁFICA 86
7 Panel de mensajes
Figura 79. Panel de mensajes.
El panel de mensajes es donde la interfaz comunica la mayoría de la
información. Como se ve en la Figura 79, el panel tiene dos partes
diferenciadas, en la parte superior el programa muestra información para
el usuario, mientras que en la parte inferior el usuario el puede introducir
información o peticiones al programa. Cuando el usuario introduce un
comando en la parte de abajo y pincha en ejecutar, la interfaz le transfiere
el comando directamente al simulador, de modo que los comandos que se
usan aquí son exactamente los mismos que con el simulador en modo
interactivo.
Figura 80. Elementos principales de la clase messages_panel.
La simplicidad del panel se ve reflejada en la Figura 80, no obstante, se
han definido unas funciones para el manejo de ciertos elementos del
panel.
MEMORIA. INTERFAZ GRÁFICA 87
7.1 Funciones de manejo de eventos
Figura 81. Panel de mensajes con eventos a manejar.
1. OnExecuteButtonClick, que también se acciona cuando el usuario
pulsa intro en la línea de entrada de comandos, lee lo introducido
por el usuario en la línea de entrada y llama a la función Execute del
objeto console.
2. OnExeFileButtonClick abre un diálogo para que el usuario elija un
fichero con comandos para el simulador, y luego se lo pasa también
a la función Execute del objeto console.
3. Clear simplemente borra el output_text.
4. OnLeftDClick se ejecuta cuando el usuario hace doble clic sobre el
output_text, y su función es detectar si se ha pinchado sobre una lína
con un error de ensamblador, y en tal caso llamar a la función
ShowError del program_panel para que se marque el error.
8 Panel principal
Los paneles ya detallados se juntan este panel que los engloba a todos,
que a su vez está incluido en el marco principal, que contiene toda la
interfaz gráfica.
MEMORIA. INTERFAZ GRÁFICA 88
Figura 82. Diseño del panel main_panel.
Como se puede deducir de la Figura 82, el panel main_panel es muy
sencillo, tan sólo tiene los “sizers” que dan la estructura a dónde debe
estar cada panel, y su flexibilidad, y dentro de cada uno de los cuatro
huecos hay punteros a los 4 paneles ya comentados.
Figura 83. Panel main_panel.
MEMORIA. INTERFAZ GRÁFICA 89
En la Figura 83 se puede apreciar el resultado final con los cuatro paneles.
9 Marco principal (“Main Frame”)
Figura 84. Marco principal del programa.
El panel principal se instancia dentro de el marco gomal del programa,
que también incluye la barra de herramientas y la barra de menús, para
dar como resultado la ventana completa de la interfaz, como se puede
observar en la Figura 84.
Figura 85. Elementos principales de la clase GUIFrame.
MEMORIA. INTERFAZ GRÁFICA 90
El marco principal se ha implementado con la clase GUIFrame, derivado
de la clase wxFrame, en la Figura 85 se puede apreciar que alberga los
objetos main_panel, console y project. La clase configure_panel, sin embargo,
no está incluida en GUIFrame ya que se abre como un diálogo, aunque se
crea desde esta clase.
9.1 Datos principales
Esta clase contiene la barra de herramientas, derivada de wxToolBar y la
barra de menús, derivada de wxMenu, además de los objetos ya
mencionados.
9.2 Funciones principales
9.2.1 LoadConfig
Figura 86. Función LoadConfig.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Tanto al querer abrir un archivo existente como uno
nuevo, abre el diálogo de configuración y le indica al configure_panel
que archivo tiene que cargar.
MEMORIA. INTERFAZ GRÁFICA 91
9.2.2 Save
Figura 87. Función Save.
• Argumentos de entrada: Ninguno.
• Argumentos de salida: Ninguno.
• Función principal: Le pide al configure_panel que guarde el archivo de
configuración del proyecto, y al program_panel (dentro de main_panel)
que guarde el archivo ensamblador. Se ejecuta cuado se pide guardar y
cuando se va a ensamblar el proyecto.
9.3 Funciones de manejo de eventos
Se han implementado funciones para manejar los eventos de la barra de
menús y la barra de herramientas, aparte de OnClose, que se ejecuta
cuando el usuario quiere cerrar el programa de cualquier manera,
pidiendo confirmación.
9.3.1 Funciones de la barra de herramientas
Figura 88. Botones de la barra de herramientas.
MEMORIA. INTERFAZ GRÁFICA 92
1. Las funciones OnNew, OnOpen y OnSave abren los diálogos para
elegir el nombre del archivo y respectivamente, abren un archivo
nuevo, abren uno existente, o guardan todo el proyecto.
2. Las funciones OnUndo y OnRedo deshacen o rehacen el último
cambio en el archivo de código del programa.
3. OnAssemble se encarga de pedirle al objeto console que llame al
ensamblador y actualiza los paneles al terminar.
4. OnInit, OnStep y OnRunTask mandan al objeto console las peticiones
de inicializar el simulador, ejecutar un paso o ejecutar una tarea.
5. Las funciones OnAddBreakpoint, OnDeleteBreakpoint y
OnDelAllBreakpoint piden al simulador que borre añada un punto de
ruptura, lo borre, o que borre todos, y al processor_panel que haga lo
propio en la tabla de la memoria ROM.
6. OnRegistersWatch, OnRegistersClear, OnRegistersUp y
OnRegistersDown llaman a las funciones Watch, Clear, Up y Down de
registers_panel.
9.3.2 Funciones de la barra de menús
Figura 89. Barra de menús.
En la barra de menús se accede a las mismas funcionalidades del
simulador que en la barra de herramientas y alguna más. En la Figura 89
se ve que está dividida en cinco partes.
9.3.2.1 File
MEMORIA. INTERFAZ GRÁFICA 93
Figura 90. Submenú File de la barra de menús.
El submenú contiene las opciones de la Figura 90, que llaman
respectivamente a las funciones OnNew, OnOpen y OnSave ya comentadas,
y a OnQuit, que intenta cerrar el programa, pero OnClose captura el evento
y pide confirmación.
9.3.2.2 Edit
Figura 91. Submenú Edit de la barra de menús.
Desde el submenú Edit se accede a deshacer o rehacer un cambio en el
código del programa ensamblador, con OnUndok y OnRedo, y al diálogo de
configuración del proyecto, a través se OnConfigure.
9.3.2.3 Assemble
Figura 92. Submenú Assemble de la barra de menús.
Tan sólo se presenta la opción de ensamblar el proyecto, usando la función
OnAssemble.
9.3.2.4 Simulate
MEMORIA. INTERFAZ GRÁFICA 94
Figura 93. Submenú Simulate de la barra de menús.
Desde el submenú Simulate se presentan las opciones que se ven en la
Figura 93, que por orden llaman a OnInit, OnStepk, OnRunTask,
OnAddBreakpoint, OnDeleteBreakpoint y OnDelAllBreakpoint, ya
comentadas, y por último la opción de que el simulador compruebe la
simulación generada por ModelSim, a través de la función OnCheckVhdl,
que simplemente pasa la petición al objeto console para que se comunique
con el simulador.
9.3.2.5 Help
Figura 94. Submenú Help de la barra de menús.
Figura 95. Diálogo de About.
MEMORIA. INTERFAZ GRÁFICA 95
El submenú Help da acceso a la opción About, que a través de la función
OnAbout abre el diálogo que se muestra en la Figura 95, en el que se
muestra la compañía y se le indica al usuario un correo electrónico donde
informar de errores en el programa.
MEMORIA. RESULTADOS / EXPERIMENTOS 96
Capítulo 5 RESULTADOS / EXPERIMENTOS
Por la naturaleza del proyecto los resultados son lo que se ha ido
especificando a lo largo de la duración del mismo, los programas
funcionan como se esperaba. Para ilustrar el funcionamiento global del
sistema se van a mostrar algunos de los ficheros y resultados por pantalla
que se obtienen al hacer una simulación simplificada del uso del
programa.
1 Datos de entrada
A continuación se presenta el programa que se simula para ilustrar el
funcionamiento:
// Código de programa ejemplo
.sys
// No hace falta inicializacion del sistema
.prog
.locate data 0x0001 ;
// direccion en la que se empiezan a escrbir los datos
// Constantes globales utiles
constant P_cero 0.0 ;
constant P_menos_uno -1.0 ;
constant P_dos 2.0 ;
// Variables del programa
variable v_b ;
variable v_b_cuadrado ;
variable v_menos_b ;
variable v_dos_por_a ;
variable v_cuatro_a_c;
variable v_raiz ;
variable v_tmp;
variable v_res_1;
variable v_res_2;
// Entradas
MEMORIA. RESULTADOS / EXPERIMENTOS 97
// Entradas secuenciales
input in_seq_1 0x0000;
input in_seq_2 0x0002;
// Entradas desde la memoria de tipo "timed" (cambia sus valores
en el tiempo)
input in_timed_1 0x0080;
input in_timed_2 0x0081;
// Salidas
//Salidas secuenciales
output out_seq_1 0x0004;
output out_seq_2 0x0008;
.begin
// Tareas (de mayor a menor prioridad)
.task 0x0 l_trap; // la tarea 0 siempre tiene la más alta
prioridad pero solo sirve para capturar excepciones
.task 0x1 l_nada ; // la tarea 1 no hace nada, pero debe saltar
cada vez que pase su periodo, pues tiene mayor prioridad que la tarea 2
.task 0x2 l_raices_pol ; // la tarea 2 calcula las raices del
polinomio (in_seq_1*x^2+in_timed_2*x+in_timed_1) y lo guarda en out_seq_1
y out_seq_2 usando la formula (-b+-sqrt(b^2-4*a*c))/(2*a)
.locate 0x0 ; // empezar a guardar las tareas en 0
// tarea 0
l_trap:
HALT;
JMP l_trap ;
// tarea 1
l_nada:
HALT;
// tarea 2
l_raices_pol:
FIN v_b , in_timed_2 ; // obtengo b
FMUL v_b_cuadrado, v_b , v_b ; // obtengo b^2
FINMUL v_dos_por_a , in_seq_1 , P_dos ; // obtengo 2*a
FINMUL v_tmp , in_timed_1, P_dos ;
FMUL v_cuatro_a_c, v_tmp , v_dos_por_a ; // obtengo 4*a*c
FSUB v_tmp , v_b_cuadrado, v_cuatro_a_c ;
FSQR v_raiz , v_tmp ; // obtengo sqrt(b^2-4*a*c)
MUL v_menos_b, v_b , P_menos_uno ; // obtengo menos b
FADD v_tmp , v_menos_b, v_raiz ;
MEMORIA. RESULTADOS / EXPERIMENTOS 98
FDIV v_res_1 , v_tmp , v_dos_por_a ; // obtengo resultado 1
FSUB v_tmp , v_menos_b, v_raiz ;
FDIV v_res_2 , v_tmp , v_dos_por_a ; // obtengo resultado 2
FOUT out_seq_1, v_res_1 ; // saco el resultado 1
FOUT out_seq_2, v_res_2 ; // saco el resultado 2
HALT;
.end
Figura 96. Comunicación al encontrar un error en el código.
Tras introducir el código, al intentar ensamblar el programa informa de
que ha encontrado un error de la manera que se indica en la Figura 96.
Figura 97. Mensaje al ensamblar sin errores, pero con advertencias.
MEMORIA. RESULTADOS / EXPERIMENTOS 99
Al arreglar el error (es FMUL, no MUL) y volver a ensamblar nos avisa de
que algunos de los símbolos definidos no se usan en el programa, como se
ve en la Figura 97, pero ensambla el código. Vamos a dejarlo así.
El ensamblador ya ha terminado su función, generando los ficheros
test.back, test.vhdl, test.map, test.eeprom, test.bin, test.dis, test.dat, test.pc y
test.config (en el final del capítulo se pueden encontrar los ficheros más
significativos), pero el programa nos informa de que no puede actualizar
los paneles, pues no encuentra los ficheros de entrada, y se cierra.
Entonces creamos unos ficheros con los datos de entrada usando un editor
de textos usando el formato correspondiente (se explican en el capítulo en
el que se tratan los esclavos del APB, Capítulo 36) y volvemos a
ensamblar.
2 Ejecutando instrucciones
Figura 98. Aspecto del programa tras ensamblar.
En la Figura 98 se puede observar el aspecto al ensamblar tras haber
creado los ficheros de entrada, mostrando los valores de las variables y el
programa y el fichero de “backannotation”.
MEMORIA. RESULTADOS / EXPERIMENTOS 100
Figura 99. Aspecto del programa tras ejecutar un paso del simulador.
Si a continuación ejecutamos un paso, ya sea escribiendo “run step” en la
entrada de comandos, pinchando sobre el icono de la flecha verde, o
apretando F9, se actualizan los paneles del programa como se puede
observar en la Figura 99. Se marca arriba a la izquierda la instrucción en la
dirección del programa que le corresponde, debajo los nuevos valores de
las variables, marcando la que ha cambiado de valor, en el centro el
“Program Counter”, el reloj, la bandera del sistema y el estado de las
tareas, y en la derecha se señala la instrucción que se ejecuta sobre el
fichero de “backannotation”.
Para ilustrar el comportamiento de las tareas se ha creado una tarea de
menor prioridad que hace unos cálculos matemáticos, y otra de mayor
prioridad que no hace nada en absoluto, pero debe entrar cada 75 ciclos de
reloj, pues así se ha configurado.
MEMORIA. RESULTADOS / EXPERIMENTOS 101
Figura 100. Ejecución de la tarea 2 con y sin cambios de tarea.
En la Figura 100 se muestra la parte de interés para ilustrar como
interactúan las dos tareas. A la izquierda está la tarea 2 ejecutándose al
completo de una vez, y a la derecha la ejecución de la tarea 2 con un salto
intermedio de la tarea 1.
Cuando se está ejecutando la tarea 2 salta la tarea 1, que como solo tiene
un halt, termina instantáneamente, dejando que el usuario escriba algo. Se
ha escrito “p clk” para que saque por pantalla el número de ciclos de reloj,
se puede comprobar que la tarea 1 se ha ejecutado inmediatamente al
acabar la instrucción que estaba en curso al llegar el reloj a 75 ciclos.
Si a continuación escribimos “run task” de nuevo, la tarea 2 sigue
ejecutándose por donde estaba, y termina correctamente.
3 Ficheros de entrada
3.1 Archivo con el código ensamblador, Prueba.asm
// Código de programa ejemplo
.sys
// No hace falta inicialización del sistema
.prog
.locate data 0x0001 ;
// direccion en la que se empiezan a escrbir los datos
MEMORIA. RESULTADOS / EXPERIMENTOS 102
// Constantes globales _tiles
constant P_cero 0.0 ;
constant P_menos_uno -1.0 ;
constant P_dos 2.0 ;
// Variables del programa
variable v_b ;
variable v_b_cuadrado ;
variable v_menos_b ;
variable v_dos_por_a ;
variable v_cuatro_a_c;
variable v_raiz ;
variable v_tmp;
variable v_res_1;
variable v_res_2;
// Entradas
// Entradas secuenciales
input in_seq_1 0x0000;
input in_seq_2 0x0002;
// Entradas desde la memoria de tipo "timed" (cambia sus valores en el
tiempo)
input in_timed_1 0x0080;
input in_timed_2 0x0081;
// Salidas
//Salidas secuenciales
output out_seq_1 0x0004;
output out_seq_2 0x0008;
.begin
// Tareas (de mayor a menor prioridad)
.task 0x0 l_trap; // la tarea 0 siempre tiene la m_s alta prioridad pero
solo sirve para capturar excepciones
.task 0x1 l_nada ; // la tarea 1 no hace nada, pero debe saltar cada vez
que pase su periodo, pues tiene mayor prioridad que la tarea 2
.task 0x2 l_raices_pol ; // la tarea 2 calcula las raices del polinomio
(in_seq_1*x^2+in_timed_2*x+in_timed_1) y lo guarda en out_seq_1 y
out_seq_2 usando la formula (-b+-sqrt(b^2-4*a*c))/(2*a)
.locate 0x0 ; // empezar a guardar las tareas en 0
// tarea 0
l_trap:
MEMORIA. RESULTADOS / EXPERIMENTOS 103
HALT;
JMP l_trap ;
// tarea 1
l_nada:
HALT;
// tarea 2
l_raices_pol:
FIN v_b , in_timed_2 ; // obtengo b
FMUL v_b_cuadrado, v_b , v_b ; // obtengo b^2
FINMUL v_dos_por_a , in_seq_1 , P_dos ; // obtengo 2*a
FINMUL v_tmp , in_timed_1, P_dos ;
FMUL v_cuatro_a_c, v_tmp , v_dos_por_a ; // obtengo 4*a*c
FSUB v_tmp , v_b_cuadrado, v_cuatro_a_c ;
FSQR v_raiz , v_tmp ; // obtengo sqrt(b^2-4*a*c)
FMUL v_menos_b, v_b , P_menos_uno ; // obtengo menos b
FADD v_tmp , v_menos_b, v_raiz ;
FDIV v_res_1 , v_tmp , v_dos_por_a ; // obtengo resultado 1
FSUB v_tmp , v_menos_b, v_raiz ;
FDIV v_res_2 , v_tmp , v_dos_por_a ; // obtengo resultado 2
FOUT out_seq_1, v_res_1 ; // saco el resultado 1
FOUT out_seq_2, v_res_2 ; // saco el resultado 2
HALT;
.end
3.2 Archivo con los datos de entrada de la memoria tipo “timed”,
Timed.apbin
0 : 0 18 , 1 fff5
30 : 0 3c , 1 ffea
60 : 0 1e , 1 ffdf
3.3 Archivo con los datos de entrada del esclavo secuencial 1,
in_seq_1.apbin
8
6
10
3.4 Archivo con los datos de entrada del esclavo secuencial 2,
in_seq_2.apbin
0
0
MEMORIA. RESULTADOS / EXPERIMENTOS 104
0
4 Ficheros generados por el programa
4.1 Archivo de proyecto, Prueba.dspp
# Configuration file for program Dsp Simulator
GLOBAL # global configuration
n_bits 24
regfile_size 0x200
rom_size 0x400
apb_size 0x8000
n_tasks 2
folder Prueba
TASK # task periods, and active/inactive bit
0 0 0 # not used
1 75 1
2 0 1
NAMES # names of the input and output files of the
program
test.dat # regfile
test.bin # rom
test.pc # initial Programm Counters of each task
test.status # status word values at each time
test.map # variables map
test.outs # input : output variables for each task
regfile.txt # input : VHDL simulation output, for checking
APB # apb slaves
slave slave_in_seq_1 seq
start 0x0
end 0x0
input in_seq_1.apbin
output _NOT_USED_
slave slave_in_seq_2 seq
start 0x2
end 0x2
input in_seq_2.apbin
MEMORIA. RESULTADOS / EXPERIMENTOS 105
output _NOT_USED_
slave slave_out_seq_1 seq
start 0x4
end 0x4
input _NOT_USED_
output out_seq_1.apbout
slave slave_out_seq_2 seq
start 0x8
end 0x8
input _NOT_USED_
output out_seq_2.apbout
slave slave_timed_mem timed
start 0x80
end 0xff
input timed.apbin
output timed.apbout
GUI_FILES # these files are not used by the simulator,
just by the GUI
test.config # assembly config file
test.vhdl # vhdl rom package file
test.eeprom # eeprom file
test.back # backannotation file
test.dis # disasssemble file
.\Prueba.asm # asssembly file
dsp_asm.exe # assembler name
dsp_sim.exe # simulator name
END
4.2 Archivo de “backannotation”, test.back
// C_digo de programa ejemplo
.sys
// No hace falta inicializaci_n del sistema
.prog
.locate data 0x0001 ;
// direccion en la que se empiezan a escrbir los
datos
// Constantes globales _tiles
0x00000001 0x00000000 constant P_cero 0.0 ;
0x00000002 0x00bf0000 constant P_menos_uno -1.0 ;
0x00000003 0x00400000 constant P_dos 2.0 ;
MEMORIA. RESULTADOS / EXPERIMENTOS 106
// Variables del programa
0x00000004 0x00000000 variable v_b ;
0x00000005 0x00000000 variable v_b_cuadrado ;
0x00000006 0x00000000 variable v_menos_b ;
0x00000007 0x00000000 variable v_dos_por_a ;
0x00000008 0x00000000 variable v_cuatro_a_c;
0x00000009 0x00000000 variable v_raiz ;
0x0000000a 0x00000000 variable v_tmp;
0x0000000b 0x00000000 variable v_res_1;
0x0000000c 0x00000000 variable v_res_2;
// Entradas
// Entradas secuenciales
0x00000000 0x00000000 input in_seq_1 0x0000;
0x00000002 0x00000000 input in_seq_2 0x0002;
// Entradas desde la memoria de tipo "timed"
(cambia sus valores en el tiempo)
0x00000080 0x00000000 input in_timed_1 0x0080;
0x00000081 0x00000000 input in_timed_2 0x0081;
// Salidas
//Salidas secuenciales
0x00000004 0x00000000 output out_seq_1 0x0004;
0x00000008 0x00000000 output out_seq_2 0x0008;
.begin
// Tareas (de mayor a menor prioridad)
0x00000000 0x00000000 .task 0x0 l_trap; // la tarea 0 siempre tiene la
m_s alta prioridad pero solo sirve para capturar excepciones
0x00000001 0x00000002 .task 0x1 l_nada ; // la tarea 1 no hace nada, pero
debe saltar cada vez que pase su periodo, pues tiene mayor prioridad que
la tarea 2
0x00000002 0x00000003 .task 0x2 l_raices_pol ; // la tarea 2 calcula las
raices del polinomio (in_seq_1*x^2+in_timed_2*x+in_timed_1) y lo guarda
en out_seq_1 y out_seq_2 usando la formula (-b+-sqrt(b^2-4*a*c))/(2*a)
.locate 0x0 ; // empezar a guardar
las tareas en 0
// tarea 0
l_trap:
0x00000000 0xf8000000 HALT;
0x00000001 0x40000000 JMP l_trap ;
MEMORIA. RESULTADOS / EXPERIMENTOS 107
// tarea 1
l_nada:
0x00000002 0xf8000000 HALT;
// tarea 2
l_raices_pol:
0x00000003 0x08110200 FIN v_b , in_timed_2 ; //
obtengo b
0x00000004 0x58140804 FMUL v_b_cuadrado, v_b , v_b ; //
obtengo b^2
0x00000005 0x101c0003 FINMUL v_dos_por_a , in_seq_1 , P_dos ; //
obtengo 2*a
0x00000006 0x10290003 FINMUL v_tmp , in_timed_1, P_dos ;
0x00000007 0x58201407 FMUL v_cuatro_a_c, v_tmp , v_dos_por_a ; //
obtengo 4*a*c
0x00000008 0x50280a08 FSUB v_tmp , v_b_cuadrado, v_cuatro_a_c ;
0x00000009 0x68241400 FSQR v_raiz , v_tmp ; // obtengo
sqrt(b^2-4*a*c)
0x0000000a 0x58180802 FMUL v_menos_b, v_b , P_menos_uno ; //
obtengo menos b
0x0000000b 0x48280c09 FADD v_tmp , v_menos_b, v_raiz ;
0x0000000c 0x602c1407 FDIV v_res_1 , v_tmp , v_dos_por_a ; //
obtengo resultado 1
0x0000000d 0x50280c09 FSUB v_tmp , v_menos_b, v_raiz ;
0x0000000e 0x60301407 FDIV v_res_2 , v_tmp , v_dos_por_a ; //
obtengo resultado 2
0x0000000f 0x08101602 FOUT out_seq_1, v_res_1 ; // saco
el resultado 1
0x00000010 0x08201802 FOUT out_seq_2, v_res_2 ; // saco
el resultado 2
0x00000011 0xf8000000 HALT;
4.3 Archivo con la ROM en vhdl, test.vhdl
-----------------------------------------------------
-- VHDL package file for the ROM
-- Automatically generated by dsp_asm
-- To fix errors: the function that generates this is
-- in source/dsp_print.c
--
-- Data written as:
-- Address
-- Value
-- Address
-- Value
MEMORIA. RESULTADOS / EXPERIMENTOS 108
-- (Beggining with address)
-----------------------------------------------------
package rom_automatic is
constant c_size_code : integer := 36;
constant c_size_task : integer := 6;
type rom_code_type is array ((c_size_code - 1) downto 0, 31 downto 0)
of std_logic;
type rom_task_type is array ((c_size_task - 1) downto 0, 31 downto 0)
of std_logic;
constant rom_code : rom_task_type := (
x"0000D000",
x"F8000000",
x"0000D001",
x"40000000",
x"0000D002",
x"F8000000",
x"0000D003",
x"08110200",
x"0000D004",
x"58140804",
x"0000D005",
x"101C0003",
x"0000D006",
x"10290003",
x"0000D007",
x"58201407",
x"0000D008",
x"50280A08",
x"0000D009",
x"68241400",
x"0000D00A",
x"58180802",
x"0000D00B",
x"48280C09",
x"0000D00C",
x"602C1407",
x"0000D00D",
x"50280C09",
x"0000D00E",
x"60301407",
x"0000D00F",
MEMORIA. RESULTADOS / EXPERIMENTOS 109
x"08101602",
x"0000D010",
x"08201802",
x"0000D011",
x"F8000000");
constant rom_task : rom_task_type := (
x"0000C000",
x"00000000",
x"0000C001",
x"00000002",
x"0000C002",
x"00000003",
);
end package rom_automatic;
4.4 Archivo con la salida del esclavo secuencial 1, out_seq_1.apbout
8
6
10
4.5 Archivo con la salida del esclavo secuencial 2, out_seq_2.apbout
3
5
1
MEMORIA. CONCLUSIONES 110
Capítulo 6 CONCLUSIONES
En el proyecto se ha conseguido crear una herramienta útil para apoyar el
desarrollo de código para los DSPs y microprocesadores de la empresa
CRISA.
Los objetivos de modularidad del diseño se han conseguido cubrir
perfectamente, aunque el objetivo de intentar realizar una portabilidad del
compilador GCC para el DSP con el que se trabaja se abandonó tras
estudiarlo y comprobar que la cantidad de tiempo que sería necesario
invertir sería muy alta, e interesaba más depurar y completar las
herramientas principales.
El resultado final obtenido tanto en el simulador como en la interfaz
gráfica ha sido mucho más completo que el definido como objetivo al
comienzo del proyecto. Objetivos nuevos han aparecido a lo largo del
curso y al final se ha conseguido una herramienta de simulación con
bastantes oportunidades que ofrecer al desarrollador.
Este documento entero, memoria del proyecto, en casi es de tanta utilidad
como los programas creados en sí; es por ello que se ha intentado explicar
clara pero detalladamente el diseño y las funciones de los programas
realizados, teniendo en mente que se trata de un proyecto que debe poder
ser modificado con facilidad. Se han creado también unos manuales para
explicar el funcionamiento de los programas de cara al usuario, y un
manual explicando como realizar los típicos pequeños cambios para
adaptar el sistema de desarrollo a cambios algo más importantes en el
proyecto con el que se trabaja.
MEMORIA. FUTUROS DESARROLLOS 111
Capítulo 7 FUTUROS DESARROLLOS
El proyecto se puede mejorar tanto con pequeños cambios sobre los
programas realizados, como con grandes cambios que faciliten el
desarrollo de código apoyándose en las herramientas del proyecto y en
otras de gran potencia.
1 Pequeños cambios
1.1 Adaptar a cambios en códigos de operación y ciclos de reloj sin
necesidad de recompilar
Se podría intentar facilitar la adaptación del programa a pequeños
cambios en el proyecto con el que se trabaja si los códigos de operación de
las instrucciones y sus ciclos de reloj se pudieran modificar sin necesidad
de volver a compilar el código.
Una manera de hacer esto sería que el usuario tuviera que guadar esta
información en un fichero externo, que tanto el ensamblador como el
simulador leyeran al iniciarse. De este modo además se evita tener los
códigos de operación definidos dos veces (una para el ensamblador y otra
para el simulador), por lo que se pueden ahorrar errores de incoherencia.
El fichero podría tener una sintaxis de este estilo:
FMUL 0x0B 2
FDIV 0x0C 2
…
Indicando para cada instrucción el código de operación y el número de
ciclos de reloj que tarda en ejecutarse.
MEMORIA. FUTUROS DESARROLLOS 112
1.2 Mejorar la escritura de código en la interfaz gráfica
La interfaz gráfica ya tiene el panel del programa, donde el usuario puede
introducir código. Pero este panel se podría mejorar hacia un editor de
textos más completo que incluyera:
• Poder enseñar números de línea a la izquierda.
• Poder buscar reemplazar palabras.
• Coloreado del código, conociendo el lenguaje. Podría identificar las
palabras que son una operación a partir del fichero arriba mencionado.
• Poder abrir y editar los textos con los valores de las señales de entrada.
1.3 Implementar las operaciones de la FPU manualmente
Este es un cambio que se piensa hacer dentro de poco, por lo que se ha
estructurado el código pensando en ello. En el fichero operations.cpp del
simulador se encuentran las operaciones que se realizan en la FPU, que de
momento están implementadas de este estilo:
uint32 OpMul(uint32 a, uint32 b)
{
float res;
res = int2float(a) * int2float(b);
return float2int(res);
}
Es decir, cuando se quiere realizar una operación con dos números se
pasan a float, se realiza la operación normal en float y se vuelven a poner
en modo uint. Las funciones int2float y float2int interpretan las entradas y
devuelven la salida como la imagen uint de números en punto flotante
codificados en 24 o en 32 bits, dependiendo de cómo esté configurado el
simulador.
El método funciona y da una buena precisión, pero para adaptarse mejor
al sistema simulado habría que implementar las funciones dentro de este
fichero tal y como tienen lugar en la FPU del DSP, es decir, con
desplazamientos, sumas, etc. También habría que cuidar excepciones y
MEMORIA. FUTUROS DESARROLLOS 113
casos especiales, como que los datos que se reciben no sean un número
valido en punto flotante, divisiones por cero y demás.
2 Grandes cambios
El sistema de desarrollo experimentaría un salto de calidad importante si
se lograran implementar algunos de los siguientes cambios:
2.1 Co-simulación con ModelSim
Con la herramienta de simulación de circuitos digitales ModelSim se puede
realizar la simulación del DSP en VHDL, que luego se puede comprobar
con el simulador de este proyecto para detectar fallos. Ahora mismo el
proceso es lento, pues primero se debe realizar la simulación con
ModelSim, para generar un fichero que luego se comprueba con el
simulador.
La alternativa de co-simulación consiste en que cada paso de simulación
(ciclo de reloj, en principio) un programa pida al otro sus resultados y
compare que son los mismos antes de seguir, de manera que ambos
simulen a la vez. Esto permite encontrar errores de manera mucho más
sencilla y rápida. En principio se podría hacer usando como programa
principal (el que pide los resultados del otro y compara) o bien el
ModelSim o el simulador de este proyecto.
2.2 Adaptación del compilador GCC
Ahora mismo el código se debe introducir en el lenguaje ensamblador del
simulador. La opción de adaptar el compilador GCC para el DSP que
simulamos permitiría escribir el código en lenguaje C, dejando que sea el
GCC el que compile el código que luego se ensamblaría con el
ensamblador del proyecto. En la referencia [11] se incluye un link a una
página web donde se explica el proceso.
MEMORIA. FUTUROS DESARROLLOS 114
2.3 Generación de código directamente con Simulink
La herramienta de simulación de Matlab, Simulink, se usa a menudo para
comprobar el resultado esperado de una tarea ejecutada en el DSP antes
de implantarla. Si se consiguiera adaptar para generar código en el
lenguaje ensamblador del DSP usado, se ahorraría tiempo y errores en
implantar el código a mano. Otra opción si ya se ha adaptado el
compilador GCC sería que generara el código en lenguaje C, dejando al
GCC el compilarlo a ensamblador.
Parte II MANUALES DE USUARIO
MANUALES DE USUARIO. MANUAL DEL ENSAMBLADOR 116
Capítulo 1 MANUAL DEL ENSAMBLADOR
El manual de usuario del ensamblador ya fue realizado por D. Jose Daniel
Muñoz Frías en su día, se incluye en el proyecto para hacerlo más
autocontenido.
This directory contents the assembler for the DSP.
1.- Compilation:
Go to the source directory and Make the executable:
> cd source
> make
These commands will build the executable and copy it to the parent
directory.
2.- Use:
The assembler takes a source file and generates a set of files with
code and
configuration data for the DSP. The files generated are:
- Code (.bin)
- Chip configuration data (.config)
- Variable initialization (.dat)
- EEPROM programming file (.eeprom)
- Tasks initial program counters (.pc)
- Listing of asm and code generated (.lst)
- Listing of variables and constants with their address mapping (.map)
3.- Source code sintaxis:
The source file is divided in several sections delimited by assembler
directives.
3.1.- Configuration data.
The first section is the chip configuration data. The beginning of the
section is defined by the .sys directive. This section only has config
data
MANUALES DE USUARIO. MANUAL DEL ENSAMBLADOR 117
which has the format:
config Config_Var_Name value address;
3.2.- Variable and constant declaration.
The second section contains the declarations of variables and constants.
The section begins with the .prog directive and there are four kind of
declarations:
variable Var_Name [%r_address];
constant Const_Name Value [%r_address];
input In_Var_Name [address];
output Out_Var_Name [address];
If the address value is not specified, the assembler assign one,
beginning
at the address 0. The variables and constants are mapped to the DSP RAM
and the input and outputs are mapped to the apb bus.
To specify an absolute address for a variable or constant the value must
be in decimal. For example:
variable foo %r_27;
declares a variable foo at the address 27.
To specify an absolute address for an input or output variable, the
address must be given in hexadecimal:
input bar 0x1CA1;
If the automatic address generation is used, it is possible to modify the
address counter with the directive locate. For example:
.locate data 0xDA
variable pepe;
will store the variable pepe at the address 0xDA. The following variables
and constants will be stored in addreses following 0xDB. To change the
address counter of the Input/Output space, the directive is .locate io.
For example:
.locate io 0x1CA1;
input bar;
will be equivalent to:
MANUALES DE USUARIO. MANUAL DEL ENSAMBLADOR 118
input bar 0x1CA1
3.3.- Code section.
The last section is the code section, delimited by the directives .begin
and
.end.
To specify the beginning of each task, the "task" directive is used:
.task 0x00 label;
where the number following the .task is tha task ID and the label is the
entry point of the task.
In the examples directory there is an example of source file and the
files generated for the assembler.
4.- Assembler use.
usage:
dsp_asm [options]
options:
-i input file (mandatory)
-o output binary file, defaults to 'a.bin'
-d output data initialization file, defaults to 'a.dat'
-p task PC initialization file, defaults to 'a.pc'
-c config file, defaults to 'a.config'
-e eeprom programming file, defaults to 'a.eeprom'
-b object-source backannotation file
-m output var and const mapping file
-v output vhdl file with rom program, defaults to 'a.vhdl'
-0 offset of config data (defaults to 0x0000)
-1 offset of constant initialization data (defaults to 0xC800)
-2 offset of code (defaults to 0xD000)
-3 offset of tasks inital pc (defaults to 0xC000)
-h print this help
example:
dsp_asm -i s.txt -o s.bin
MANUALES DE USUARIO. MANUAL DEL SIMULADOR 119
Capítulo 2 MANUAL DEL SIMULADOR
El siguiente manual se encuentra en la carpeta del proyecto del simulador
como “ReadMe.txt”
1. - Executing:
Call the program from the command prompt specifying an input
configuration file, for example:
>> dsp_simulator -c dsp_simulator.config
And optionally, you can also specify an input commands file, for
example:
>> dsp_simulator -c dsp_simulator.config -i dsp_simulator.cmd
In this mode, the program will execute the commands in the file, and
if there are no errors, it will close itself.
You can also specify an output file to put the log:
>> dsp_simulator -c dsp_simulator.config -i dsp_simulator.cmd
-o dsp_simulator.log
2. - Commands
These are the commands understood by the dsp simulator:
- exit : exit the program
- help, - h : prints the list of commands
- init : initializes all system, returns apb and regfile memories,
PC, clk ticks and task states to initial values
- run : runs a specified part of he code. you have to specify:
* run step : executes 1 step
* run step (number): execute that number of steps
* run task : execute until task is halted
* run clk (number) : execute steps until clk reaches (number)
* run clk another (number) : execute for another (number) clk cycles
- print, -p : prints information of the dsp simulation. you have to
specify:
* print PC: prints current system Program Counter
MANUALES DE USUARIO. MANUAL DEL SIMULADOR 120
* print ticks: prints the number of clock cycles since the start of
the simulation
* print task : Prints state of all tasks
* print task (number) : Prints state of task with id (number)
* print regfile : Prints contents of all regfile
* print regfile (number):Prints contents of regfile in dir (number)
* print rom : Prints contents of all rom
* print rom (number) : Prints contents of rom in dir (number)
* print apb : Prints contents of all apb
* print status : Prints status word
* print state : Prints all of the dsp state info
- disassemble (number) : Prints instruction in dir (number)
- disassemble all (file) : Prints all disassembled code in file
- breakpoint add (number): Adds breakpoint in the position (number)
- breakpoint delete (number): Deletes the breakpoint in the position
(number)
- breakpoint delete all : Deletes all breakpoints
- tolerance (number) : Set tolerance for error of output from VHDl
simulation (default to 1e-10)
- VHDL : Check output from the VHDL simulation
3. - Configuration file:
In this file you have to specify information about the Dsp, divided
into 3 sections:
- Global: regfile, rom and apb sizes, and number of tasks
- Names: names of the rest of the input files of the program, in a
specific order
- Apb: information about the apb slaves, you can specify as many
slaves as you want, must all information is required for every slave.
Slaves can be memory (mem), sequential (seq) and timed (timed)
ALL THIS INFORMATION IS REQUIRED IN THE CONFIGURATION FILE.
The program allows comments in this file, of the type: # blablabla
Example of configuration file:
# Configuration file for program Dsp Simulator
GLOBAL # global configuration
MANUALES DE USUARIO. MANUAL DEL SIMULADOR 121
n_bits 24
regfile_size 0x200
rom_size 0x400
apb_size 0x8000
n_tasks 5
folder prueba
TASK # task periods, and active/inactive bit
0 0 0 # not used
1 0 1
2 0 0
3 0 0
4 0 0
5 2000000 1
NAMES # names of the input and output files of the program
test.dat # regfile
test.bin # rom
test.pc # initial Programm Counters of each task
test.status # status word values at each time
test.map # variables map
test.outs # input : output variables for each task
regfile.txt # input : VHDL simulation output, for checking
APB # apb slaves
slave slave_1 mem
start 0x0
end 0x1ff
input mem.apbin
output mem.apbout
GUI_FILES # these files are not used by the simulator, just by the GUI
test.config # assembly config file
test.vhdl # vhdl rom package file
test.back # backannotation file
test.dis # disasssemble file
.\instr_nuevas.asm # asssembly file
END
MANUALES DE USUARIO. MANUAL DE LA INTERFAZ GRÁFICA 122
Capítulo 3 MANUAL DE LA INTERFAZ GRÁFICA
El siguiente manual también se puede encontrar como “ReadMe.txt” en la
carpeta que contiene los tres proyectos de CodeBlocks y la carpeta con los
ejecutables.
En éste directorio se encuentran el ensamblador y el simulador del DSP
1.- Estructura de carpetas
En el directorio se encuentran 4 carpetas:
- Assembler: contiene el código fuente del ensamblador, junto con el
archivo de proyecto del CodeBlocks, también contiene un manual del uso
del ensamblador (ReadMe.txt) sin necesidad de la interfaz gráfica.
- Console: contiene el código fuente del simulador en modo consola,
junto con el archivo de proyecto del CodeBlocks, también contiene un
manual del uso del simulador (ReadMe.txt) sin necesidad de la interfaz
gráfica.
- GUI: contiene el código fuente de la interfaz gráfica, junto con el
archivo de proyecto del CodeBlocks
- working_dir: contiene los programas compilados, junto con las dll
necesarias para su ejecución
2.- Uso:
Ejecutar directamente el archivo DspSim.exe de la carpeta working_dir,
que es la interfaz gráfica.
- Crear un nuevo proyecto o abrir uno ya creado.
Habrá que configurar los nombres de ficheros del programa, incluyendo
el del programa en ensamblador, se pueden dejar los nombres por defecto
Si se especifica un nombre de fichero en ensamblador que no existe,
el programa lo creará en blanco.
- Cuando el programa en ensamblador esté creado, si se le da al botón
de ensamblar, se quejará de los errores que encuentre, al arreglarlo es
posible que aparezcan más errores que no se habían detectado en la pasada
anterior.
MANUALES DE USUARIO. MANUAL DE LA INTERFAZ GRÁFICA 123
- Una vez no haya errores, el programa se compilará y automáticamente
cargará los valores del programa, registros APB en los paneles de la
interfaz.
En la ventana de arriba a la izquierda se puede ver el programa tal y
como está ordenado en memoria, con cada instrucción en hexadecimal, y su
traducción.
Para añadir breakpoints, se debe pulsar la dirección en la que se
quiere añadir y pinchar en el símbolo +, o bien darle a Simulate > Add
breakpoint
Se pueden quitar pinchando en la dirección, y dándole al símbolo - o
al símbolo x, que quita todos los breakpoints. También se puede con el
menú Simulate
En medio se encuentra información básica del DSP, como son el PC, el
reloj, el flag y las tareas.
Abajo a la izquierda están los registros y el apb, y una pestaña que
se llama watched, donde se pueden poner las variables que interesen de
los registros y del APB, para no tener que ir buscándolas.
Para añadirlas hay que pinchar en el nombre de la variable, y luego
al símbolo de Watch variable, para quitarlas hay que encontrarla en la
pestaña de Watched, pinchar en el nombre y en Clear from watched.
También se pueden reorganizar el orden en el que aparecen en la
pestaña watched, pinchando en el nombre de una o varias, y luego en las
flechas.
En azul claro se muestran las variables cuyo valor ha cambiado desde
la última instrucción realizada.
Arriba a la derecha está el fichero de texto con el programa en
ensamblador, antes de ensamblar. Después cambia solo al Backannotation
file, que contiene lo mismo que el fichero de texto, con la codificación
de cada instrucción a la izquierda.
Los cambios que se quieran hacer en el programa se han de realizar en
la pestaña de Asm program, el backannotation file es de sólo lectura.
En la zona de abajo a la derecha está la ventana donde el programa da
los errores, y muestra las comunicaciones relevantes entre la GUI y el
simulador modo consola.
Se pueden introducir comandos directamente, para ver una lista de los
comandos disponibles se ha de escribir el comando help en ésta zona.
- Las instrucciones que le pueden ejecutar son:
* Inicializar (el reloj de arena), que devuelve el dsp al completo a
su estado inicial
MANUALES DE USUARIO. MANUAL DE LA INTERFAZ GRÁFICA 124
* Run step (la flecha verde), que ejecuta una sóla instrucción del
dsp
* Run task (la flecha verde con la barra verde debajo) que ejecuta la
tarea hasta encontrar un breakpoint, o un halt en la tarea.
* Ejecutar la comprobación de la simulación de VHDL, en el menú
Simulate>Check VHDL Simulation. Para ello deben encontrarse en el
directorio del proyecto los ficheros:
- VHDL log file, contra el cual se realizará la comprobación
- Task outputs file, que contendrá las salidas a comprobar en cada
tarea en el formato:
1 variable_a_comprobar_1, variable_a_comprobar_2, var_a_comp_3
2 variable_a_comprobar_4
3 variable_a_comprobar_5, variable_a_comprobar_6
... (Todas las tareas)
3.- Sintaxis del ensamblador:
En la carpeta Assembler se puede encontrar un ReadMe con la sintaxis
del ensamblador.
Las operaciones son las siguientes:
nop:
No hace nada, sólo incrementa en PC en 1.
halt:
Para la tarea actual, guarda el contexto y avisa al Task Manager.
fin arg1, arg2:
Mueve el dato de la dirección arg2 del APB a la dirección arg2 del
regfile.
fout arg1, arg2:
Mueve el dato de la dirección arg2 del regfile a la dirección arg2
del APB.
inout arg1, arg2:
Mueve el dato de la dirección arg2 del APB a la dirección arg2 del
APB.
finmul arg1, arg2, arg3:
Escribe en la dirección arg1 del regfile el resultado de lo que
está en la dirección arg2 del APB multiplicado por lo que está en la
dirección arg3 del regfile.
foutmul arg1, arg2, arg3:
Escribe en la dirección arg1 del APB el resultado de lo que está en
la dirección arg2 del regfile multiplicado por lo que está en la
dirección arg3 del regfile.
mov arg1, arg2:
MANUALES DE USUARIO. MANUAL DE LA INTERFAZ GRÁFICA 125
Mueve dentro del regfile el dato de la dirección arg2 a la
dirección arg1.
movc arg1, arg2:
Mueve dentro del regfile el dato de la dirección arg2 a la
dirección arg1 si la bandera del sistema está a 1.
movnc arg1, arg2:
Mueve dentro del regfile el dato de la dirección arg2 a la
dirección arg1 si la bandera del sistema está a 0.
movgz arg1, arg2, arg3:
Mueve dentro del regfile el dato de la dirección arg2 a la
dirección arg1 si arg3 es mayor que cero.
movlz arg1, arg2, arg3:
Mueve dentro del regfile el dato de la dirección arg2 a la
dirección arg1 si arg3 es menor que cero.
cmpgt arg2, arg3:
Compara dos registros y si arg2 es mayor que arg3 pone la bandera a
1.
cmplt arg2, arg3:
Compara dos registros y si arg2 es menor que arg3 pone la bandera a
1.
cmpeq arg2, arg3:
Compara dos registros y si arg2 es igual que arg3 pone la bandera a
1.
cmpge arg2, arg3:
Compara dos registros y si arg2 es mayor o igual que arg3 pone la
bandera a 1.
cmple arg2, arg3:
Compara dos registros y si arg2 es menor o igual que arg3 pone la
bandera a 1.
jmp dst_jmp:
Salta a la dirección de memoria dst_jmp.
jmpc dst_jmp:
Salta a la dirección de memoria dst_jmp si la bandera vale 1.
jmpnc dst_jmp:
Salta a la dirección de memoria dst_jmp si la bandera vale 0.
jmps dst_jmp, arg3:
Salta a la dirección de memoria dst_jmp si el bit arg3 de la
palabra de status vale 1.
fadd arg1, arg2, arg3:
Escribe en la dirección arg1 del regfile el resultado de lo que
está en la dirección arg2 más lo que está en la dirección arg3 del
regfile.
fsub arg1, arg2, arg3:
MANUALES DE USUARIO. MANUAL DE LA INTERFAZ GRÁFICA 126
Escribe en la dirección arg1 del regfile el resultado de lo que
está en la dirección arg2 menos lo que está en la dirección arg3 del
regfile.
fmul arg1, arg2, arg3:
Escribe en la dirección arg1 del regfile el resultado de lo que
está en la dirección arg2 multiplicado por lo que está en la dirección
arg3 del regfile.
fdiv arg1, arg2, arg3:
Escribe en la dirección arg1 del regfile el resultado de lo que
está en la dirección arg2 dividido por lo que está en la dirección arg3
del regfile.
fsqrt arg1, arg2:
Escribe en la dirección arg1 del regfile el resultado de la raíz
cuadrada de lo que está en la dirección arg2.
fsin arg1, arg2:
Escribe en la dirección arg1 del regfile el resultado del seno de
lo que está en la dirección arg2.
fcos arg1, arg2:
Escribe en la dirección arg1 del regfile el resultado del coseno de
lo que está en la dirección arg2.
fsatp arg1, arg2, arg3:
Si arg3 es mayor o igual que arg2, escribe en la dirección arg1 del
regfile lo que está en la dirección arg2 del regfile, si no, escribe lo
que está en la dirección arg3 del regfile.
fsatn arg1, arg2, arg3:
Si arg3 es menor o igual que arg2, escribe en la dirección arg1 del
regfile lo que está en la dirección arg2 del regfile, si no, escribe lo
que está en la dirección arg3 del regfile.
fabs arg1, arg2:
Escribe en la dirección arg1 del regfile el valor absoluto de lo
que está en la dirección arg2.
MANUALES DE USUARIO. MANUAL PARA ADAPTAR EL SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS 127
Capítulo 4 MANUAL PARA ADAPTAR EL
SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS
Como ya se ha comentado con anterioridad, el poder adaptar el sistema de
desarrollo a proyectos diversos o a cambios dentro de un proyecto con
relativa facilidad es clave para la utilidad del proyecto, con la intención de
facilitarlo lo más posible se explica en este capítulo como realizar cambios
típicos en el sistema de desarrollo.
1 Qué hace falta recompilar y cómo
Figura 101. Partes del sistema de desarrollo.
La interfaz gráfica está pensada para que sea lo más independiente posible
de los cambios que haya que realizar, por lo tanto en los cambios típicos
que se van a comentar en este capítulo no será necesario tocar nada de
ella, sin embargo el simulador hará falta cambiarlo para los tres cambios
que se comentan y el simulador para los dos segundos, cambiar los
códigos de operación y cambiar el set de instrucciones.
Primero se explica muy brevemente cómo realizar la compilación en sí, y
más adelante que hay que cambiar dentro del código fuente.
MANUALES DE USUARIO. MANUAL PARA ADAPTAR EL SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS 128
1.1 Cómo recompilar el ensamblador
La manera más simple es usar el archivo de proyecto de CodeBlocks que
está incluido en la carpeta “Assembler” dentro de la carpeta del proyecto,
ya que tiene configurado lo que se indica a continuación.
La otra vía, para quien no quiera usar el CodeBlocks, sería la siguiente:
1. Correr el programa bison usando el “parser” como argumento
(enlace en la referencia [4]):
bison –vd dsp_parser.y
2. A continuación se debe ejecutar el programa flex con el escáner del
dsp como argumento (un enlace para bajarlo se puede encontrar en
la referencia [3]):
flex dsp_scanner.lex
3. Ya tenemos generados los ficheros dsp_parser.tab.h, dsp_parser.tab.c y
lex.yy.c, con lo que simplemente tenemos que usar cualquier
compilador para que compile todos los archivos de la carpeta.
1.2 Cómo recompilar el simulador
El simulador no tiene nada de especial, de modo que se puede compilar
usando el proyecto de Codeblocks de la carpeta “Console” o por cualquier
otro método.
2 Cambiar ciclos de reloj de cada instrucción
Es el cambio más sencillo, tan sólo hay que abrir el fichero operations.h de
la carpeta del simulador (“Console”) y cambiarlo en éste fichero, para
luego recompilar el simulador.
3 Cambiar códigos de operación
Cambiar los códigos de operación requiere pequeños cambios en ambos
ejecutables antes de recompilar.
MANUALES DE USUARIO. MANUAL PARA ADAPTAR EL SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS 129
• En el ensamblador el fichero a cambiar es dsp_inst.h.
• En el simulador hace falta modificar operations.h.
4 Cambiar el set de instrucciones
Este cambio requiere profundizar un poco más en el código fuente. Los
pasos a seguir serían los siguientes (puesto que implica el uso de los
programas flex y bison, puede ser útil la referencia [5], en la que se cita un
tutorial básico sobre su uso):
4.1 Cambiar el fichero de entrada del programa bison
En el fichero dsp_parser.y se le indica al programa bison cual es la sintaxis
de nuestro código en ensamblador, habrá que detallarle que “tokens”
puede encontrarse al leer el código. En la parte superior del fichero se
listan los ”tokens”, como se muestra a continuación:
%token TOK_FCOS
Hay que reservar uno por cada instrucción.
El siguiente paso es definir la sintaxis de la instrucción, para ello en la
parte de abajo del fichero definimos qué se espera encontrar tras en
“token” de la instrucción y cual es la función del ensamblador que se
encarga ya qué se le debe pasar, en el ejemplo de a continuación la función
coseno tiene dos operandos detrás separados por una coma, al encontrarlo
(al pasar sobre el código por segunda vez) se debe pasar a la función del
ensamblador que se encarga de las funciones trigonométricas indicando
que es un coseno, y pasando los argumentos 2 y 4 de la línea de
instrucción (el 3 es la coma).
| TOK_FCOS operand ',' operand
{
if (asm_pass == 2){
if (assemble_fsxx(CODOP_FCOS, $2, $4)) return 1;
}
MANUALES DE USUARIO. MANUAL PARA ADAPTAR EL SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS 130
4.2 Cambiar el fichero de entrada del programa flex
El fichero dsp_scanner.lex es el fichero en el que le indicamos al programa
flex que palabras debe reconocer el simulador, de modo que le tenemos
que indicar cuales son los nombres de las instrucciones y que “tokens”
debe pasar al analizador sintáctico al identificarlas.
mov|MOV {return TOK_MOV;}
Hacer el cambio de este fichero es muy sencillo, tan sólo hay que definir
que palabras representan la instrucción, en el ejemplo de arriba se expresa
que al encontrar “mov” o “MOV” se debe pasar el “token”
correspondiente a la instrucción.
4.3 Cambiar los ficheros dsp_inst.h y dsp_inst.c
A continuación toca indicar al ensamblador como se ensambla cada
instrucción. En el fichero dsp_inst.h se enumeran las funciones que se
llaman desde el fichero dsp_parser.y, siguiendo con el ejemplo del coseno:
int assemble_fsxx(int op_code, struct t_op* rt, struct t_op* rs1);
Los argumentos de entrada son el código de operación, para saber si es
una instrucción de seno, de coseno o de raíz cuadrada, ya que esta función
ensambla las tres, y los dos operandos encontrados.
En la función assemble_fsxx se comprueba que ambos operandos son
correctos, se genera el código de instrucción y se crea una estructura con
toda la información de la instrucción, que se manda a la cola de
instrucciones.
Para añadir nuevas instrucciones hay que crear una función similar a la
descrita para la nueva instrucción y hacer que se la llame desde
dsp_parser.y. Una vez hecho ya se puede compilar el ensamblador de
nuevo.
MANUALES DE USUARIO. MANUAL PARA ADAPTAR EL SISTEMA DE DESARROLLO A DISTINTOS
PROYECTOS 131
4.4 Cambiar el simulador
En el fichero operations.h se deben indicar los ciclos de reloj de la
instrucción y su código de operación como se muestra a continuación:
const uint8 code_fcos = 0X10;
const uint8 fcos_clk = 6;
Y si la instrucción es aritmética como en este caso hay que crear la función
especial que se llama para realizarla en operations.cpp, declarándola en
operations.h.
Luego hay que programar que se debe cambiar en el sistema al ejecutar la
instrucción modificando la instrucción DecoAndExe del fichero dsp.cpp. La
función tiene un switch en función del código de operación, en el que se
saca por pantalla la operación, se realiza y se aumentan el PC y el reloj del
sistema. Este es el código para la instrucción del coseno:
case code_fcos:
cout << " fcos " << hex << arg1 << ", " << hex << arg2 << endl;
regfile_ptr->Read(arg2, &data2);
result = OpCos(data2);
regfile_ptr->Write(arg1, result);
PC++;
clk_tick += fcos_clk;
break;
El último cambio que hay que realizar es la función Disassemble del fichero
sim.cpp, que devuelve la operación sin necesidad de ejecutarla en el
sistema.
case code_fcos:
str = " fcos " + int2strhex(arg1) + ", " + int2strhex(arg2);
break;
Ya se puede recompilar el simulador, por lo que la instrucción está
implantada.
BIBLIOGRAFÍA
BIBLIOGRAFÍA 133
BIBLIOGRAFÍA
[1] Entorno de desarrollo multiplataforma de código abierto, CodeBlocks:
http://www.codeblocks.org/
[2] Conjunto de compiladores del proyecto GNU, GCC:
http://gcc.gnu.org/
[3] Herramienta para generar analizadores léxicos, flex:
http://flex.sourceforge.net/
[4] Herramienta para generar analizadores sintácticos, bison:
http://www.gnu.org/software/bison/
[5] Tutorial sobre el uso de flex y bison:
http://webdiis.unizar.es/asignaturas/LGA/material_2004_2005/Intro_F
lex_Bison.pdf
[6] Herramienta en diseño de Interfaces Gráficas, wxWidgets:
www.wxwidgets.org
[7] Tutorial de compilación y configuración de wxWidgets con CodeBlocks bajo
Windows:
http://wiki.codeblocks.org/index.php?title=Compiling_wxWidgets_2.8.6
_to_develop_Code::Blocks_(MSW)
Y bajo Linux:
http://wiki.codeblocks.org/index.php?title=Installing_Code::Blocks_fro
m_source_on_Linux
[8] Tutorial básico de uso de wxWidgets junto con CodeBlocks para diseñar de
forma gráfica:
http://wiki.codeblocks.org/index.php?title=WxSmith_tutorials
[9] Tutorial de uso de las funciones de wxWidgets:
http://zetcode.com/tutorials/wxwidgetstutorial/
[10] Funcionamiento de la tuberías o pipes:
BIBLIOGRAFÍA 134
http://www.reloco.com.ar/linux/prog/pipes.html
[11] Manual para portar el GCC:
http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_toc.html
Parte III ESTUDIO ECONÓMICO
ESTUDIO ECONÓMICO 136
El sistema de desarrollo creado en este proyecto no se va a vender, por lo
que su rentabilidad económica depende principalmente de los ahorros que
le supone a la empresa EADS Astrium CRISA.
El objetivo de los programas realizados es optimizar y agilizar el proceso
de diseño y depuración de código para DSPs, creando unas herramientas
abiertas, y con un código bien estructurado, facilitando los futuros
desarrollos. El permitir a desarrollador escribir, ensamblar y simular los
programas diseñados dentro de una misma interfaz gráfica, con las
opciones de vigilar unas variables en concreto, poner puntos de ruptura y
demás comodidades, ayuda a desarrollar y depurar los programas mucho
más eficientemente.
Las herramientas se han desarrollado teniendo un proyecto en concreto en
mente, pero también pensando en su fácil adaptación. Por lo tanto
podemos concluir que van a poder ser usadas en bastantes proyectos
dentro del departamento de Microelectrónica de CRISA, justificándose el
coste de su ejecución en el hecho de que ahorrará tiempo de desarrollo a
largo plazo.