3. HERRAMIENTA PARA LA CODIFICACIÓN xHDL

Anuncio
3. HERRAMIENTA PARA LA CODIFICACIÓN xHDL
3.1 Introducción
El diseño del filtro en xHDL (hardware design language) permite acelerar el desarrollo final del
sistema en una ASIC (application-specific integrated circuit) o en una FPGA (field programable
gate array).
Esta herramienta va a permitir generar el lenguaje de descripción hardware (HDL) asociado al
filtro en punto fijo diseñado. Son estos HDLs (tales como VHDL, Verilog, etc…) los lenguajes
usados por los diseñadores hardware para permitir el diseño del sistema a nivel hardware.
Este proceso de conversión del diseño del filtro en punto fijo a un lenguaje de descripción
hardware lo realiza MATLAB de manera casi inmediata y muy sencilla. Gracias a esta
herramienta que simplifica enormemente la codificación del diseño en lenguaje xHDL, se puede
dedicar más tiempo a otras fases del desarrollo del filtro.
3.2 Propiedades
Como entrada a esta herramienta se necesita un filtro cuantificado, como los que se obtienen al
utilizar la herramienta de diseño de filtros que se ha estudiado en el apartado anterior. Los filtros
cuantizados deben tener alguno de los siguientes formatos:
•
•
En punto fijo con signo o sin signo.
En punto flotante de doble precisión.
Esta herramienta sólo permite la implementación del filtro que posee una de las siguientes
estructuras:
•
•
•
•
•
•
•
•
FIR (finite impulse response)
FIR antisimétricos
FIR transpuestos
FIR simétricos
Respuesta impulsiva infinita IIR implementada usando SOS en forma directa I.
IIR implementada usando SOS en forma directa I transpuesta.
IIR implementada usando SOS en forma directa II
IIR implementada usando SOS en forma directa II transpuesta.
Como salida de la conversión del filtro en lenguaje hardware se obtienen varios ficheros, según
se especifique en las propiedades de configuración de la herramienta. El lenguaje de
descripción hardware utilizado en la conversión también se debe especificar al inicio del
proceso. Si se escoge lenguaje ‘Verilog’, el resultado de la codificación será almacenado en un
fichero con extensión ‘.v’, en cambio si es el lenguaje ‘VHDL’ el seleccionado, se obtendrá un
fichero con extensión ’.vhd’.
Por defecto se colocan los ficheros generados en el subdirectorio llamado ‘hdlsrc’ del directorio
de trabajo en el que MATLAB se encuentre.
MATLAB ofrece al usuario varias formas de trabajar con esta herramienta de codificación en
lenguaje xHDL. Así se encuentra una interfaz gráfica a modo de ventanas que simplifica
enormemente el proceso llamada ‘fdatool’. Ésta también permite llevar a cabo la cuantificación
del filtro en punto fijo además de muchas cosas más.
Otra forma es la habitual inserción de las órdenes a través de la línea de comandos de
MATLAB. Así para generar el fichero resultado se teclea la funcione ‘generatehdl’.
Otras opciones de configuración que se deben especificar antes de iniciar el proceso y por tanto
a tener en cuenta antes de generar el código asociado al filtro se pasan a especificar en los
siguientes subapartados.
3.2 1 Propiedades asociadas a las opciones de ‘reset’
- ‘Reset type’
Asíncrono o síncrono; determina el tipo de reset usado al generar el código HDL asociado a
los registros. El usar uno u otro depende del tipo de tecnología que se vaya a usar para
implementar el diseño en lenguaje HDL ( es decir si se busca obtener una ASIC o FPGA )
Por defecto su valor es asíncrono.
- ‘Reset asserted level’
Valor activo para la señal reset de entrada; determina si el valor del reset debe ser ‘1’ o ‘0’
para activar el reseteo de todos los registros del filtro del diseño del filtro.
Por defecto su valor es ‘1’.
3.2.2 Propiedades asociadas a los puertos
En cuanto a las propiedades asociadas a los puertos del sistema aparecen:
-
-
‘Nombre asignado a los puertos del sistema’
Por defecto, se tiene que el codificador del diseño del filtro en xHDL asigna los
siguientes nombres a los puertos del filtro implementado en hardware:
- Puerto de entrada : filter_in
- Puerto de salida : filter_out
- Puerto del reloj : clk
- Puerto habilitador del reloj : clk_enable
- Puerto del reset : reset
‘Tipo aplicable a los datos con los que trabajan los puertos’
Los puertos son interfaces que se encargan de transformar los tipos de datos con
los que se trabaja en la generación de código hardware a tipos de datos compatibles con
tipos MATLAB. Por tanto cada puerto es definido como un tipo de dato permitido en
código hardware.
En cuanto a los tipos utilizados en la generación de código hardware se destacan
los siguientes que serán los dados por defecto:
-
Std_logic : Transforma el dato recibido a un dato que corresponda con
el estado lógico deseado.
-
Std_logic_vector : Un vector de caracteres del tipo ‘Std_logic’
definidos anteriormente.
-
Wire : Pasa la señal de entrada sin llevar a cabo sobre ella ningún
procesamiento.
Así la herramienta de codificación del diseño del filtro en lenguaje HDL declara
el tipo de dato del puerto de entrada y salida del filtro a ‘std_logic_vector’ en
VHDL y a tipo ‘wire’ al trabajar con Verilog. Este tipo de dato se puede
modificar al trabajar con VHDL, pero no ocurre lo mismo con Verilog en donde
el tipo esta fijado a ‘wire’ y no se puede cambiar.
- ‘Add input register’ y ‘Add output register’
Estas dos opciones permiten añadir un registro extra de entrada o salida durante la
generación del código HDL. Esto es útil cuando la aplicación presenta requerimientos de
tiempo, de manera que sea necesario añadir una latencia extra, por ejemplo estableciendo
que la salida se almacene en el registro de salida cuanto un evento de reloj fijado tenga
lugar y el reloj general del sistema tenga valor ‘1’.
3.2.3
HDL
Propiedades avanzadas asociadas con la optimización del diseño
Algunas de las propiedades de optimización pueden dar lugar a datos numéricos que difieran de
los resultados obtenidos con el filtro cuantificado del que se partía para la generación del código
HDL.
- ‘Optimizing for HDL’
Por defecto, el codificador HDL produce un código que es compatible con los resultados
numéricos obtenidos con el filtro cuantificado. Si se quiere obtener un código HDL que esté
más optimizado en cuanto a velocidad de reloj o requisitos de espacio del diseño se activará
esta propiedad, a costa de obtener resultados que difieran de los originales procedentes del
filtro cuantificado ya que elimina operaciones extra de cuantificación.
- ‘Coefficient Multipliers’
Especifica el tipo de procesamiento que sufren los coeficientes antes de la multiplicación;
por defecto esta herramienta genera un código que contiene operaciones de multiplicación
siendo el valor de esta propiedad es ‘multiplier’.
Otros posibles valores serían ‘CSD’ y ‘factored-CSD’, estas dos últimas opciones permiten
obtener una velocidad de reloj mayor y un área de diseño menor, ya que optimizan las
multiplicaciones realizándolas mediante desplazamientos y sumas, pero se tendrá la
posibilidad de obtener valores que difieran de los originales cuando ocurran situaciones de
saturación o redondeo.
- ‘FIR adder style’
Especifica el tipo de suma final que va a ser implementada en filtros FIR; por defecto se
implementa un sumador lineal que es la opción vista y explicada en la mayor parte de los
textos que versan sobre DSP.
Otra opción posible para la implementación es la opción ‘pipeline’ o ‘tree’, que ofrece un
velocidad de reloj mayor pero menos exactitud en la operaciones numéricas.
Comparando las opciones se llega a que el número de sumas llevadas a cabo para la forma
‘lineal’ y ‘tree’ son las mismas, pero el tiempo que toma el llevarlas a cabo es menor con la
opción ‘tree’ al presentar un procesamiento en paralelo y no secuencial como el que
presenta la opción ‘lineal’. ‘Pipeline’ optimiza la frecuencia de reloj a costa de incrementar
el tiempo de latencia del filtro ya que introduce un conjunto de registros adicionales. El
modo ‘linear’ es el que asegura mayor exactitud numérica en comparación con el filtro
original.
Una vez fijadas todos los parámetros de configuración pertinentes según los resultados
deseados, la generación del código asociado al filtro cuantificado es instantánea.
3.3 Ejemplo práctico
Se muestra a continuación un ejemplo práctico con los resultados en lenguaje VHDL obtenidos
de un filtro FIR cuantificado en punto fijo con los siguientes parámetros:
Discrete-Time FIR Filter (real)
-- ------------------------------Filter Structure : Direct-Form FIR
Filter Order
: 15
Stable
: Yes
Linear Phase
: Yes (Type 1)
Arithmetic
: fixed
CoeffWordLength : 16
CoeffAutoScale : true
Signed
: true
InputWordLength : 16
InputFracLength : 15
OutputWordLength : 16
OutputMode
: 'AvoidOverflow'
ProductMode
: 'FullPrecision'
AccumMode
: 'FullPrecision'
RoundMode
OverflowMode
: 'convergent'
: 'wrap'
En cuanto a la configuración de la herramienta de generación de código en lenguaje xHDL, se
empieza con la dada por defecto que asegura la máxima exactitud numérica del código HDL
obtenido con respecto al filtro en punto fijo del que se parte. Los resultados obtenidos son los
que a continuación aparecen:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.ALL;
ENTITY filini IS
PORT( clk
clk_enable
reset
filter_in
filter_out
);
:
:
:
:
:
IN std_logic;
IN std_logic;
IN std_logic;
IN std_logic_vector(15 DOWNTO 0); -- sfix16_En15
OUT std_logic_vector(15 DOWNTO 0) -- sfix16_En11
END filini;
-----------------------------------------------------------------Module Architecture: filini
---------------------------------------------------------------ARCHITECTURE rtl OF filini IS
-- Local Functions
-- Type Definitions
TYPE delay_pipeline_type IS ARRAY (NATURAL range <>) OF signed(15 DOWNTO 0); -sfix16_En15
-- Constants
CONSTANT coeff1
CONSTANT coeff2
CONSTANT coeff3
CONSTANT coeff4
CONSTANT coeff5
CONSTANT coeff6
CONSTANT coeff7
CONSTANT coeff8
CONSTANT coeff9
CONSTANT coeff10
CONSTANT coeff11
CONSTANT coeff12
CONSTANT coeff13
CONSTANT coeff14
CONSTANT coeff15
CONSTANT coeff16
CONSTANT coeff17
-- Signals
SIGNAL delay_pipeline
SIGNAL product16
SIGNAL product14
SIGNAL product13
SIGNAL product12
SIGNAL product11
SIGNAL product10
SIGNAL product9
SIGNAL product8
SIGNAL product7
SIGNAL product6
SIGNAL product5
SIGNAL product4
SIGNAL product2
SIGNAL sum1
SIGNAL add_temp
SIGNAL sum2
SIGNAL add_temp_1
SIGNAL sum3
SIGNAL add_temp_2
SIGNAL sum4
SIGNAL add_temp_3
SIGNAL sum5
SIGNAL add_temp_4
SIGNAL sum6
SIGNAL add_temp_5
SIGNAL sum7
SIGNAL add_temp_6
SIGNAL sum8
SIGNAL add_temp_7
SIGNAL sum9
SIGNAL add_temp_8
SIGNAL sum10
: signed(15 DOWNTO 0) := to_signed(0, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(-44, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(0, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(718, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(3071, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(7715, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(13975, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(19578, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(21845, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(19578, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(13975, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(7715, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(3071, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(718, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(0, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(-44, 16); -- sfix16_En17
: signed(15 DOWNTO 0) := to_signed(0, 16); -- sfix16_En17
: delay_pipeline_type(0 TO 16); -- sfix16_En15
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(31 DOWNTO 0); -- sfix32_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(32 DOWNTO 0); -- sfix33_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
SIGNAL add_temp_9
SIGNAL sum11
SIGNAL add_temp_10
SIGNAL sum12
SIGNAL add_temp_11
SIGNAL output_typeconvert
SIGNAL output_register
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(36 DOWNTO 0); -- sfix37_En32
: signed(37 DOWNTO 0); -- sfix38_En32
: signed(15 DOWNTO 0); -- sfix16_En11
: signed(15 DOWNTO 0); -- sfix16_En11
BEGIN
-- Block Statements
Delay_Pipeline_process : PROCESS (clk, reset)
BEGIN
IF reset = '1' THEN
delay_pipeline(0 TO 16) <= (OTHERS => (OTHERS => '0'));
ELSIF clk'event AND clk = '1' THEN
IF clk_enable = '1' THEN
delay_pipeline(0) <= signed(filter_in);
delay_pipeline(1 TO 16) <= delay_pipeline(0 TO 15);
END IF;
END IF;
END PROCESS Delay_Pipeline_process;
product16 <= delay_pipeline(15) * coeff16;
product14 <= delay_pipeline(13) * coeff14;
product13 <= delay_pipeline(12) * coeff13;
product12 <= delay_pipeline(11) * coeff12;
product11 <= delay_pipeline(10) * coeff11;
product10 <= delay_pipeline(9) * coeff10;
product9 <= delay_pipeline(8) * coeff9;
product8 <= delay_pipeline(7) * coeff8;
product7 <= delay_pipeline(6) * coeff7;
product6 <= delay_pipeline(5) * coeff6;
product5 <= delay_pipeline(4) * coeff5;
product4 <= delay_pipeline(3) * coeff4;
product2 <= delay_pipeline(1) * coeff2;
add_temp <= resize(product2, 33) + resize(product4, 33);
sum1 <= resize( add_temp, 37);
add_temp_1 <= resize(sum1, 38) + resize(product5, 38);
sum2 <= add_temp_1(36 DOWNTO 0);
add_temp_2 <= resize(sum2, 38) + resize(product6, 38);
sum3 <= add_temp_2(36 DOWNTO 0);
add_temp_3 <= resize(sum3, 38) + resize(product7, 38);
sum4 <= add_temp_3(36 DOWNTO 0);
add_temp_4 <= resize(sum4, 38) + resize(product8, 38);
sum5 <= add_temp_4(36 DOWNTO 0);
add_temp_5 <= resize(sum5, 38) + resize(product9, 38);
sum6 <= add_temp_5(36 DOWNTO 0);
add_temp_6 <= resize(sum6, 38) + resize(product10, 38);
sum7 <= add_temp_6(36 DOWNTO 0);
add_temp_7 <= resize(sum7, 38) + resize(product11, 38);
sum8 <= add_temp_7(36 DOWNTO 0);
add_temp_8 <= resize(sum8, 38) + resize(product12, 38);
sum9 <= add_temp_8(36 DOWNTO 0);
add_temp_9 <= resize(sum9, 38) + resize(product13, 38);
sum10 <= add_temp_9(36 DOWNTO 0);
add_temp_10 <= resize(sum10, 38) + resize(product14, 38);
sum11 <= add_temp_10(36 DOWNTO 0);
add_temp_11 <= resize(sum11, 38) + resize(product16, 38);
sum12 <= add_temp_11(36 DOWNTO 0);
output_typeconvert <= resize( shift_right(sum12(36 DOWNTO 0) + ( "0" & (sum12(21) & NOT
sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) &
NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21)
& NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT
sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) & NOT sum12(21) &
NOT sum12(21))), 21), 16);
Output_Register_process : PROCESS (clk, reset)
BEGIN
IF reset = '1' THEN
output_register <= (OTHERS => '0');
ELSIF clk'event AND clk = '1' THEN
IF clk_enable = '1' THEN
output_register <= output_typeconvert;
END IF;
END IF;
END PROCESS Output_Register_process;
-- Assignment Statements
filter_out <= std_logic_vector(output_register);
END rtl;
Una vez obtenido el código del filtro en lenguaje hardware de manera automática tras
especificar los valores iniciales para las distintas propiedades de la herramienta, se pasa a hacer
uso de un sintetizador, en este caso el ‘Symplicity-Pro’ es del que se hará uso, que ofrecerá una
estimación de la cantidad de recursos hardware usados en la implementación del filtro, además
de la frecuencia de reloj máxima que se consigue con el diseño. En este caso particular,
trabajando con el filtro ‘filini’ y una ‘Virtex 2 XC2V1000’ de Xilinx, se obtienen los siguientes
resultados:
Cell usage:
I/O Register bits:
0
Register bits not including I/Os: 272 (2%)
Mapping Summary:
Total LUTs: 1601 (15%)
Process took 10.625 seconds realtime,
10.675 seconds cputime
Estimated Frequency : 46.8 MHz
Estimated Period : 21.366
3.4 Conclusiones capítulo 3
En este tercer capítulo se ha presentado la herramienta para la codificación del diseño del filtro
en xHDL de MATLAB.
Ha resultado ser una herramienta eficaz y sencilla para la codificación de diseños en lenguaje
hardware.
Resulta también un interfaz imprescindible que sirve de puente entre la herramienta de diseño
de filtros en punto fijo y el sintetizador hardware que se va a usar en la implementación y que se
ve con más detalle en el próximo capítulo 4 de aplicación.
Descargar