El propósito de este proyecto es el de ilustrar el proceso de diseño de un coprocesador que soporta el cálculo de la distancia euclidiana entre vectores de 1024 palabras de 8 bits cada una. El proyecto se desarrolló usando las siguientes herramientas:
- Software Vitis HLS 2021.1
- Software Vivado 2021.1
- Software MATLAB R2021a
- Tarjeta de desarrollo Nexys 4 DDR
El sistema operativo utilizado fue Windows 10 / Windwos 11.
Los tiempos estimados de síntesis e implementación fueron tomados operando en un computador con las siguientes caracterisiticas:
- Procesador: Intel Core i7-10750H CPU @ 2.60GHz
- Memoria (RAM): 12 GB @ 2933 MHz
Para reproducir la síntesis del coprocesador mediante Vitis HLS se utilizan los archivos fuente que se encuentran en la carpeta \SRC_VITIS_HLS
dentro de este repositorio. Se deben seguir las instrucciones descritas a continuación:
-
Abrir Vitis HLS 2021.1, seleccionando la opción
Create Project
. -
Elegir un nombre y ubicación para el proyecto creado y hacer click en el botón
Next >
. -
Añadir los archivos fuente correspondientes a archivos de diseño, estos son
EucHW.cpp
,EucHW.h
yspecs.h
. En esta misma ventana se debe definir la función principal, en este caso,EucHW
. Luego hacer click en el botónNext >
. -
Añadir los archivos fuente correspondientes a archivos de testbench, estos son
EucSW.cpp
,EucSW.h
yEucTB.cpp
. Luego hacer click en el botónNext >
. -
Elegir nombre para la solución, escoger el periodo del reloj a utilizar en la síntesis (se conserva el valor por defecto de 10 ns para obtener un estimado del timing comparable con el esperado al cargar el diseño en la taejta).
-
En la sección
Part Selection
,Parts
, especificar la tarjeta en la cual se implementará el diseño, en este casoXC7A100TCSG324-1
. -
Conservar la configuración por defecto en la sección
Flow Target
y hacer click en el botónFinish
- Sintetizar el proyecto haciendo click en el botón
Run
de la barra superior del Software oRun C Synthesis
ubicado en la secciónFlow Navigator
.
Si todo ha ido como corresponde, la síntesis debiese entregar resultados satisfactorios como los que se muestran en la Figura siguiente, cumpliendo con las restricciones de timing (sin slack negativo), y un uso de recursos fisicamente implementable en la tarjeta de desarrollo a utilizar.
- Para validar el diseño se ejecuta la Cosimulación haciendo click en botón de
Run Cosimulation
ubicado en la secciónFlow Navigator
.
Con este diseño se espera un error debido a que se está trabajando con datos del tipo entero, y se están comparando con datos flotantes para la validación. Sin embargo el error obtenido se encuentra por debajo del 1%.
La función hls::sqrt
perteneciente a la biblioteca hls_math.h tambien influye en este error, pero su uso se justifica ya que esta función permite disminuir la latencia del procesador en 16 ciclos respecto a la función sqrt
de la librería cmath
que si bien es más precisa impone un overhead a la latencia del sistema. En el caso de usar datos del tipo flotantes, el error se reduce casi en su totalidad, pero la latencia aumenta significativamente.
- Exportar IP hacienco click en el botón
Export RTL
en la secciónFlow navigator
. Esta acción genera un archvio .zip, el cual al ser descomprimido puede ser añadido a un proyecto enVivado
como se mostrará más adelante.
En esta sección se explica el uso de los pragmas implementados al realizar la sección anterior, siguiendo la función definida en \SRC_VITIS_HLS\EucHW.cpp
.
-
pragma ARRAY_MAP
Este comando combina varios arreglos de datos en un único arreglo mas largo conformado por la concatenación de los arreglos originales.
El comando soporta dos formas de mapeo para los arreglos generados, concatenación vertical y horizontal.
-
pragma ARRAY_PARTITION
Este comando separa un arreglo de datos y genera arreglos más pequeños o de un solo elemento almacenandolos en bloques de memoria RAM individuales. Esto mejora el throughtput del diseño, ya que aumenta la cantidad de datos leidos/escritos por cada ciclo de reloj, a costa de requerir más instancias de memorias/registros para almacenar datos. -
pragma ARRAY_RESHAPE
Este comando combina los efectos de los dos antes descritos, aplicando una separación del arreglo de entrada en arreglos de un elemento cada uno (pragma ARRAY_PARTITION
), y concatena elementos de los arreglos en forma vertical (pragma ARRAY_MAP
). De esta forma reduce el uso de bloques de memoria pero preserva el acceso paralelo a los datos.
Sintaxis del comando:
#pragma HLS array_reshape variable=<name> <type> factor=<int> dim=<int>
Esta directiva soporta tres configuraciones para el parámetro type
: block, cyclic y complete , y el parámetro factor
especifica la cantidad de grupos en la que se separarán los elementos del arreglo de entrada. La distribución resultante de los elementos de entrada se muestra en la siguiente Figura, considedrando un factor 2
como ejemplo.
Esta directiva además, facilitó la integración de este diseño de procesador con el proyecto hecho en Vivado, la cual que se detalla más adelante.
pragma UNROLL
Esta directiva soporta desenrollamiento total del loop, generando una copia del cuerpo de este para cada iteración considerada en su declaración, permitiendo que todas las instancias se ejecuten de mandera simultánea, y también soporta desenrollamiento parcial mediante el parámetrofactor <N>
mediante el cual se generanN
copias del cuerpo del loop reduciendo el número de iteraciones a el numero de iteraciones originales dividido porN
. Se escogió unfactor 512
como configuración de la directiva para que coincida con la distribución generada por el comandoARRAY_RESHAPE
y así aprovechar el paralelismo de manera óptima en cuanto a ingreso de datos y procesamiento de los mismos.
Finalmente la función main
del diseño queda como se muestra a continuación:
void eucHW (T A[LENGTH], T B[LENGTH], Tout *C)
{
#pragma HLS ARRAY_RESHAPE variable=A type=cyclic factor=512 dim=1
#pragma HLS ARRAY_RESHAPE variable=B type=cyclic factor=512 dim=1
uint26_t result=0;
sumLoop:for(int i=0;i<LENGTH;i++)
{
#pragma HLS UNROLL factor=512
result += (A[i]-B[i])*(A[i]-B[i]);
}
*C= hls::sqrt(result);
return;
}
Para reproducir la implementación del coprocesador mediante Vivado se utilizan los archivos fuente en la carpeta \SRC_VIVADO_DESIGN
dentro de este repositorio siguiendo las instrucciones mostradas a continuación:
- Abrir Vivado y crear un nuevo proyecto con
Create Project
. - En la sección
Project name
elegir un nombre y directorio para el proyecto. Avanzar. - En la secció
Project type
conservar las configuraciones por defecto (RTL project
marcado y todas las demas casillas desmarcadas). - En
Add Source
click enAdd Directories
y seleccionar la carpeta\SRC_VIVADO_DESIGN\VIVADO_SRC\src
que se encuentran en este repositorio. - En
Add Constraints
click enAdd File
y seleccionar el archivo\SRC_VIVADO_DESIGN\VIVADO_SRC\constraint\Nexys-4-DDR-Master.xdc
presente en el respoitorio. - En
Default Part
,Boards
elegirNexys4 DDR
, si es necesario, descargar y Finalizar.
- En el menu
PROJECT MANAGER
ir aIP Catalog
. - En la ventana
IP Catalog
hacer click derecho y elegir la opcionAdd Repository...
- Elegir la carpeta
\SRC_VIVADO_DESIGN\IP_SRC_eucHW\eucDistHW_512
. Esta carpeta deberia ser equivalente a la creada en el tutorial en VITIS HLS.
-
En el menu
PROJECT MANAGER
secciónPROGRAM AND DEBUG
hacer click en generar el Bitstream y esperar a que el archivo.bit
se haya generado correctamente. -
En la misma sección hacer click en
Open Hardware Manager
>>Open Target
>>autoconnect
>>Program Device
para cargar elbitstream
a la tarjeta.
Usando el script de MATLAB \MATLAB\coprocessorTesting.m
, que se encuentra en el repositorio, se pueden enviar vectores a la tarjeta para que sean almacenados, además, se puede ejecutar el calculo de la distancia euclidiana y recibir el resultado entregado por el procesador.
Adicionalmente, se programó el script de Matlab \MATLAB\coprocessorTesting_all.m
, también disponible en el repositorio, el cual genera 1000 instancias de prueba, donde se obtiene un error promedio de 0.24 con respecto a los resultados esperados según la misma operación desarrollada por software.
El proyecto se implemento con una frecuencia de 100 MHz. Los resultados finales muestran que con este valor se cumplen todas las restricciones de timepo, logrando un WNS de 0.081 ns, como se muestra en la Figura siguiente:
Con el diseño implementado se logró una latencia para el desarrollo del cálculo de la distancia euclidiana entre dos vectores de 16 ciclos, donde 6 de esos ciclos corresponden al cálculo de la raiz cuadrada inherente a la operación realizada. Esto se logró medir agregando el IP Intrgrated logic analizer (ILA) al diseño en Vivado. Obteniendo el diagrama temporal que se muestra a continuación.
Donde la señal superior indica el comienzo de la operación y la inferior indica cuando esta ya generó el resultado correspondiente.
Considerando que la frecuencia de reloj utilizada es de 100 Mhz y el procesador tarda 16 ciclos en entregar un resultado, se concluye que el throughtput obtenido es de 62.500.000 resultado/s
El uso de recursos se muestra en la Figura siguiente:
Esta utilización se logró con las configuraciones por defecto tanto para síntesis e implementación en Vivado, no fue necesario aplicar optimizaciones de ningún tipo.
- Sintesis (HLS) = 4 minutos 38 segundos
- Sintesis (Vivado) = 5 minutos 40 segundos
- Implementacion = 10 minutos 47 segundos
Los tiempos de síntesis e implementación fueron obtenidos directamente del software Vivado, mientras que el tiempo de síntesis del software HLS se obtuvo midiendo el tiempo con un cronómetro externo de forma manual.