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_3Como 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_bcdComo 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