Otra técnica muy usada es la de comparar nuestra implementación contra una implementación de más alto nivel. La implementación de alto nivel se supone que es correcta y se trata de corroborar que nuestra implementación VHDL coincide. A la implementación de referencia se la suele denominar golden model. Esta técnica no es opuesta a la anterior y ambas pueden utilizarse en conjunto. Es de gran utilidad cuando lo que deseamos comprobar es complejo o bien deseamos probar muchos o todos los valores posibles de entrada.
La implementación del modelo de referencia abstracto puede realizarse en forma externa a nuestro banco de pruebas. Esto se puede hacer utilizando una gran cantidad de herramientas, algunos ejemplos comunes son C/C++, SystemC, MATLAB, etc. En este caso necesitaremos tomar los valores externos, esto se explica en la siguiente sección.
La implementación de nuestro conversor de BCD a Aiken es tan simple que es impensable una versión más abstracta. Por otro lado una prueba exhaustiva tampoco requiere de vectores muy grandes. Por lo que no es un caso en el cual se obtenga una ganancia importante. De todas maneras, y con fines ilustrativos, mostraremos como realizar este tipo de prueba usando el Ejemplo 5-1. A los fines de utilizar un algoritmo diferente se optó por implementar una verificación basada en el hecho de que el código Aiken es un código de peso 2-4-2-1. Esto implica que los tres bits menos significativos tienen el mismo peso que en binario, por lo que podemos computarlos de la misma manera que un unsigned. Sólo es necesario tener en cuenta que el peso del bit 3 es 2 en lugar de 8. La implementación propuesta se muestra en el Ejemplo 5-6.
Ejemplo 5-6. Comparación contra un modelo de referencia (t_b2a_3.vhdl)
library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity T_B2A_3 is end entity T_B2A_3; architecture Simulador of T_B2A_3 is -- Declaración del componente a probar component BCD2Aiken is port( A : in std_logic_vector(3 downto 0); B : out std_logic_vector(3 downto 0)); end component BCD2Aiken; -- Señales auxiliares signal entrada : std_logic_vector(3 downto 0):="0000"; signal salida : std_logic_vector(3 downto 0); begin -- Instancia del dispositivo a probar DUT : BCD2Aiken port map(A => entrada, B => salida); -- Proceso secuencial que realiza las pruebas pruebas: process variable valor : integer; begin report "Probando el conversor de BCD a Aiken" severity note; for i in 0 to 9 loop entrada <= std_logic_vector(to_unsigned(i,4)); wait for 1 ns; -- Los 3 bits inferiores tienen el mismo peso que el binario (421) valor:=to_integer(unsigned(salida(2 downto 0))); -- El bit más pesado tiene peso 2 en lugar de 8 if salida(3)='1' then valor:=valor+2; else assert salida(3)='0' report "Bit 3 no es ni 1 ni 0" severity failure; end if; assert valor=i report "Falla para "& integer'image(to_integer(unsigned(entrada))) severity failure; end loop; for i in 10 to 15 loop entrada <= std_logic_vector(to_unsigned(i,4)); wait for 1 ns; assert salida="XXXX" report "No es XXXX para "& integer'image(to_integer(unsigned(entrada))) severity failure; end loop; report "Prueba exitosa!" severity note; wait; end process pruebas; end architecture Simulador; -- Entity: T_B2A_3
Como ejemplo sincrónico mostraremos la validación de una máquina de estados. Tomaremos como
ejemplo una máquina de estados mostrada en los apuntes. Se trata de un circuito que sirve para
verificar si un dígito BCD es válido. Los datos ingresan en serie por la entrada Y
,
el bit menos significativo primero. Luego de haber ingresado los cuatro bits la salida
Z
indica con un 1 si la combinación es incorrecta. La máquina de estados
utilizada para solucionar este problema se puede observar en la Figura 5-1.
Los valores indicados junto a las transiciones corresponden a Y/Z
.
La implementación de dicha máquina de estados se muestra en el Ejemplo 5-7.
La misma es equivalente a la entidad ejemplo3
del apunte, sólo posee cambios
menores orientados a hacer un poco más simple la lectura del código.
Ejemplo 5-7. Implementación de la máquina de estados (check_bcd.vhdl)
library IEEE; use IEEE.std_logic_1164.all; entity check_bcd is port( Y, clk, MR : in std_logic; Z : out std_logic); end entity check_bcd; architecture d2proc of check_bcd is type tipo_estado is (a, b, d, e, h, i); signal estado, estaprox : tipo_estado; begin secuencial: process (clk, MR) begin if MR='1' then estado <= a; elsif rising_edge(clk) then estado <= estaprox; end if; end process secuencial; combinacional: process (Y, estado) begin Z <= '0'; estaprox <= a; case estado is when a => estaprox <= b; when b => if Y='0' then estaprox <= d; else estaprox <= e; end if; when d => if Y='0' then estaprox <= h; else estaprox <= i; end if; when e => estaprox <= i; when h => null; when i => Z <= Y; when others => Z <= 'X'; end case; end process combinacional; end architecture d2proc; -- Entity: check_bcd
Como modelo de referencia utilizaremos una simple comparación: el dígito es válido si es menor
que 10. El test bench propuesto se muestra en el Ejemplo 5-8. Notar que el test bench
verifica todas las combinaciones posibles de cuatro bits. Por cada una inyecta en serie el valor por la
entrada Y
, en el último bit verifica que la salida Z
coincida
con lo esperado. También se verifica que Z
sea 0 el resto del tiempo.
Ejemplo 5-8. Verificación de la máquina de estados (t_check_bcd.vhdl)
library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; library std; use std.textio.all; entity T_Check_BCD is end entity T_Check_BCD; architecture Simulador of T_Check_BCD is component check_bcd is port( Y, clk, MR : in std_logic; Z : out std_logic); end component check_bcd; constant FREQ_CLK : integer:=50; -- Frecuencia del reloj en MHz constant PERI_CLK : time:=1 us/FREQ_CLK; signal clk : std_logic; -- Reloj signal detener : boolean:=false; -- Termina el test signal rst : std_logic; -- Pulso de reset signal y : std_logic; -- Entrada del DUT signal z : std_logic; -- Salida del DUT begin gen_reloj: process begin clk <= '1', '0' after PERI_CLK/2; wait for PERI_CLK; if detener then wait; end if; end process gen_reloj; rst <= '1', '0' after PERI_CLK*3/2; dut : check_bcd port map( clk => clk, MR => rst, Y => y, Z => z); do_test: process variable l : line; variable bin : unsigned(3 downto 0); begin write(l,string'("* Probando la máquina de estados")); writeline(output,l); wait until rst='0'; -- Barrer todas las combinaciones for i in 0 to 15 loop bin:=to_unsigned(i,4); -- Ingresar los bits for j in 0 to 3 loop y <= bin(j); -- Inyectar el bit wait until rising_edge(clk); -- Sincronizar -- Verificar if j=3 then -- En el bit más pesado se indica si es válido o no if i<10 then -- Valores válidos assert z='0' report "Encendido para "&integer'image(i) severity failure; else -- Valores inválidos assert z='1' report "Apagado para "&integer'image(i) severity failure; end if; else -- En el resto de los bits debería ser Z='0' assert z='0' report "No es 0 para un bit intermedio: "& integer'image(i)&" bit "&integer'image(j) severity failure; end if; end loop; end loop; write(l,string'("* Todo OK!")); writeline(output,l); detener <= true; wait; end process do_test; end architecture Simulador; -- Entity: T_Check_BCD