Probablemente más fácilmente.
Obtienes el gran parte del diseño en simulación antes de pasar al hardware .
Utilice bancos de pruebas de autocomprobación (o técnicas de verificación de orden superior, incluidas PSL, pruebas aleatorias restringidas o OSVVM ) en la función de pruebas unitarias para verificar Que el bloque cumpla con su funcionalidad básica.
Cuando no lo hace, el simulador tiene un visor de forma de onda que puede mostrarle el valor de cada señal en cada momento, mostrando de forma útil incógnitas ("X" o "Z", por ejemplo) en rojo. Use esto juiciosamente para trabajar desde los resultados incorrectos hasta su causa; edite, compile, vuelva a simular, etc. hasta que el bloque haga lo que usted quiere.
Los bancos de prueba de autocomprobación pueden comparar el diseño de bajo nivel (sintetizable) con un modelo algorítmico de nivel superior: cualquier algoritmo básico que puede escribir en C también puede escribirse en VHDL (¡pero puede que no sea sintetizable!) o el banco de pruebas puede leer los resultados esperados de un archivo. Los bancos de pruebas son, por lo tanto, sólo para el desarrollo. (Generalmente, no tienen acceso a las entrañas de un bloque de hardware; solo son entradas y salidas, por lo que son probadores de caja negra). Pero un banco de pruebas puede conectar varias cajas negras para probar cómo interactúan.
Entonces, compare los resultados reales de un bloque con los resultados esperados (es posible que necesite almacenar los resultados esperados hasta que estén listos). Esto normalmente se hace con una declaración de afirmación:
VHDL ayuda mucho gracias a tener un sistema de tipo decente: ¡úselo!
(O frustrado luchando contra él: ¡tu elección!)
Mal VHDL:
addr : integer;
...
assert addr >= 0 report "Address arithmetic overflow" severity FAILURE;
Mejor VHDL:
subtype address is natural range 0 to 2**16 - 1;
addr : address;
La afirmación ahora es redundante porque el simulador lo hace por usted: los valores fuera del rango especificado están atrapados. (La síntesis aún puede generar desbordamientos; las herramientas de sintetizadores pueden asumir que ya tiene el diseño correcto. Por lo tanto, no desperdiciarán el hardware en las comprobaciones de desbordamiento a menos que las codifique explícitamente)
Puedes hacer muchas cosas buenas con el sistema de tipos: esto debería ser una segunda naturaleza para los desarrolladores de SW, pero parece que ya no se enseña.
Un par de ejemplos:
variable mem : array(addr) of integer;
for i in addr loop
mem(i) := 0;
end loop;
El tamaño de la matriz y los límites de bucle definidos por el tipo: sin errores de bucle o sobrecargas de búfer.
assert addr'high + 1 = 65536 report "Wrong address size" severity failure;
Los atributos
('alto,' bajo, 'rango (define un subtipo entero), etc., permiten la introspección en tiempo de ejecución del tipo (establecer límites de bucle para una matriz sin restricciones, etc.) o como aquí para verificar las suposiciones sobre un tipo declarado en otro lugar. ..
type colour is (red, green, blue);
un poco como una enumeración de C excepto ...
type RGB is array(colour) of real;
constant gain : RGB := (red => 0.31, green => 0.58, blue => 0.11);
signal YUV,RGB_in : RGB;
...
for c in colour loop
YUV(c) <= RGB_in(c) * gain(c);
end loop;
habiendo definido un tipo de este tipo, puede usarlo como un índice de matriz o un bucle sobre él, etc. Y así sucesivamente.
La asociación con nombre para argumentos, componentes de matriz, etc. reduce errores y aclara el código.
Los paquetes ... reúnen los tipos y sus operaciones en componentes reutilizables seguros. Y así sucesivamente ...
Mis diseños tienden a tener un paquete "común" que define cosas ampliamente utilizadas como "dirección" arriba: todo lo usa y si cambio el tamaño de la dirección, todos los bucles se reajustan al nuevo tamaño, y cualquier cosa con supuestos codificados debería caer en una aserción (como se indica arriba) hasta que lo arregle ...