verilog Tutorial
Empezando con verilog
Buscar..
Observaciones
Verilog es un lenguaje de descripción de hardware (HDL) que se utiliza para diseñar, simular y verificar circuitos digitales a un nivel de transferencia de registro o de comportamiento. Es digno de mención por razones que lo distinguen de los lenguajes de programación "tradicionales":
- Hay dos tipos de asignación, bloqueo y no bloqueo, cada uno con sus propios usos y semántica.
- Las variables deben declararse como de ancho de bit único o con un ancho explícito.
- Los diseños son jerárquicos, con la capacidad de instanciar módulos que tienen un comportamiento deseado.
- En la simulación (no típicamente en la síntesis),
wire
variables dewire
pueden estar en uno de cuatro estados: 0, 1, flotante (z
) y no definido (x
).
Versiones
Versión | Fecha de lanzamiento |
---|---|
Verilog IEEE-1364-1995 | 1995-01-01 |
Verilog IEEE-1364-2001 | 2001-09-28 |
Verilog IEEE-1364.1-2002 | 2002-12-18 |
Verilog IEEE-1364-2005 | 2006-04-07 |
SystemVerilog IEEE-1800-2009 | 2009-12-11 |
SystemVerilog IEEE-1800-2012 | 2013-02-21 |
Instalación o configuración
Las instrucciones detalladas sobre cómo configurar o instalar Verilog dependen de la herramienta que utilice, ya que hay muchas herramientas de Verilog.
Introducción
Verilog es un lenguaje de descripción de hardware (HDL) utilizado para modelar sistemas electrónicos. Más comúnmente describe un sistema electrónico en el nivel de transferencia de registro (RTL) de abstracción. También se utiliza en la verificación de circuitos analógicos y circuitos de señal mixta. Su estructura y principios principales (como se describe a continuación) están diseñados para describir e implementar con éxito un sistema electrónico.
- Rigidez
Un circuito electrónico es una entidad física que tiene una estructura fija y Verilog se adapta para eso. Los módulos (módulo), los puertos (entrada / salida / entrada), las conexiones (cables), los bloques (@always), los registros (reg) están todos fijos en el momento de la compilación. El número de entidades e interconexiones no cambia dinámicamente. Siempre hay un "módulo" en el nivel superior que representa la estructura del chip (para la síntesis), y uno en el nivel del sistema para la verificación. - Paralelismo
Las operaciones simultáneas inherentes en el chip físico se imitan en el lenguaje mediante los bloques always (most commmon), initial y fork / join.
module top();
reg r1,r2,r3,r4; // 1-bit registers
initial
begin
r1 <= 0 ;
end
initial
begin
fork
r2 <= 0 ;
r3 <= 0 ;
join
end
always @(r4)
r4 <= 0 ;
endmodule
Todas las declaraciones anteriores se ejecutan en paralelo dentro de la misma unidad de tiempo.
Sincronización y sincronización
Verilog admite varias construcciones para describir la naturaleza temporal de los circuitos. Los tiempos y retrasos en los circuitos se pueden implementar en Verilog, por ejemplo, mediante construcciones #delay. De manera similar, Verilog también se adapta a circuitos y componentes síncronos y asíncronos como fracasos, cierres y lógica combinatoria utilizando varias construcciones, por ejemplo, bloques "siempre". Un conjunto de bloques también se puede sincronizar a través de una señal de reloj común o un bloque puede activarse en función de un conjunto específico de entradas.#10 ; // delay for 10 time units always @(posedge clk ) // synchronous always @(sig1 or sig2 ) // combinatorial logic @(posedge event1) // wait for post edge transition of event1 wait (signal == 1) // wait for signal to be 1
Incertidumbre
Verilog soporta algunas de las incertidumbres inherentes a los circuitos electrónicos. "X" se utiliza para representar el estado desconocido del circuito. "Z" se utiliza para representar el estado no impulsado del circuito.reg1 = 1'bx; reg2 = 1'bz;
Abstracción
Verilog apoya el diseño en diferentes niveles de abstracción. El nivel más alto de abstracción para un diseño es el Nivel de transferencia de registro (RTL), el siguiente es el nivel de puerta y el más bajo el nivel de celda (User Define Primitives), siendo la abstracción RTL la más utilizada. Verilog también admite el nivel de comportamiento de abstracción sin tener en cuenta la realización estructural del diseño, que se utiliza principalmente para la verificación.
// Example of a D flip flop at RTL abstraction
module dff (
clk , // Clock Input
reset , // Reset input
d , // Data Input
q // Q output
);
//-----------Input Ports---------------
input d, clk, reset ;
//-----------Output Ports---------------
output q;
reg q;
always @ ( posedge clk)
if (~reset) begin
q <= 1'b0;
end else begin
q <= d;
end
endmodule
// And gate model based at Gate level abstraction
module and(input x,input y,output o);
wire w;
// Two instantiations of the module NAND
nand U1(w,x, y);
nand U2(o, w, w);
endmodule
// Gate modeled at Cell-level Abstraction
primitive udp_and(
a, // declare three ports
b,
c
);
output a; // Outputs
input b,c; // Inputs
// UDP function code here
// A = B & C;
table
// B C : A
1 1 : 1;
0 1 : 0;
1 0 : 0;
0 0 : 0;
endtable
endprimitive
Hay tres casos de uso principales para Verilog. Ellos determinan la estructura del código y su interpretación y también determinan los conjuntos de herramientas utilizados. Las tres aplicaciones son necesarias para la implementación exitosa de cualquier diseño de Verilog.
- Diseño Físico / Back-end
Aquí, Verilog se usa para ver principalmente el diseño como una matriz de puertas interconectadas que implementan un diseño lógico. RTL / lógico / Diseño pasa por varios pasos desde la síntesis -> ubicación -> construcción del árbol de reloj -> enrutamiento -> DRC -> LVS -> a la cinta. Los pasos y secuencias precisos varían según la naturaleza exacta de la implementación. - Simulación
En este caso de uso, el objetivo principal es generar vectores de prueba para validar el diseño según la especificación. El código escrito en este caso de uso no necesita ser sintetizable y permanece dentro de la esfera de verificación. El código aquí se asemeja más a estructuras de software genéricas como para / while / do loops etc. - Diseño
El diseño implica implementar la especificación de un circuito generalmente en el nivel de abstracción RTL. El código de Verilog se proporciona para la verificación y el código completamente verificado para la implementación física. El código se escribe utilizando solo las construcciones sintetizables de Verilog. Cierto estilo de codificación RTL puede causar una falta de coincidencia entre la simulación y la síntesis y se debe tener cuidado para evitarlos.
Hay dos flujos principales de implementación. También afectarán la forma en que se escribe e implementa el código Verilog. Ciertos estilos de codificación y ciertas estructuras son más adecuados en un flujo sobre el otro.
- ASIC Flow (circuito integrado específico de la aplicación)
- Flujo de FPGA (matriz de compuerta programable en campo) - incluye FPGA y CPLD
Hola Mundo
Este ejemplo utiliza el compilador verilog icarus.
Paso 1: Crea un archivo llamado hello.v
module myModule();
initial
begin
$display("Hello World!"); // This will display a message
$finish ; // This causes the simulation to end. Without, it would go on..and on.
end
endmodule
Paso 2. Compilamos el archivo .v usando icarus:
>iverilog -o hello.vvp hello.v
El modificador -o asigna un nombre al archivo de objeto de salida. Sin este interruptor, el archivo de salida se llamaría a.out. El hello.v indica el archivo fuente que se compilará. Prácticamente no debe haber salida cuando compila este código fuente, a menos que haya errores.
Paso 3. Ya está listo para simular este programa de verilog de Hello World. Para ello, invoca como tal:
>vvp hello.vvp
Hello World!
>
Instalación de Icarus Verilog Compiler para Mac OSX Sierra
- Instalar Xcode desde la App Store.
- Instalar las herramientas de desarrollo de Xcode
> xcode-select --install
Esto proporcionará herramientas básicas de línea de comandos como gcc
y make
- Instale los puertos Mac
https://www.macports.org/install.php
El paquete de instalación OSX Sierra proporcionará un método de código abierto para instalar y actualizar paquetes de software adicionales en la plataforma Mac. Piensa yum
o apt-get
para Mac.
- Instala icarus usando puertos Mac
> sudo port install iverilog
- Verificar la instalación desde la línea de comando.
$ iverilog
iverilog: no source files.
Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
[-g1995|-g2001|-g2005] [-g<feature>]
[-D macro[=defn]] [-I includedir] [-M depfile] [-m module]
[-N file] [-o filename] [-p flag=value]
[-s topmodule] [-t target] [-T min|typ|max]
[-W class] [-y dir] [-Y suf] source_file(s)
See the man page for details.
$
Ahora está listo para compilar y simular su primer archivo Verilog en la Mac.
Instale GTKWave para la visualización gráfica de los datos de simulación en Mac OSx Sierra
GTKWave es un paquete de visualización gráfica con todas las funciones que admite varios estándares de almacenamiento de datos gráficos, pero también es compatible con VCD, que es el formato que vvp
. Entonces, para recoger GTKWave, tienes un par de opciones
- Vaya a http://gtkwave.sourceforge.net/gtkwave.zip y descárguelo. Esta versión suele ser la última.
- Si ha instalado MacPorts ( https://www.macports.org/ ), simplemente ejecute
sudo port install gtkwave
. Esto probablemente querrá instalar en las dependencias a. Tenga en cuenta que este método normalmente le dará una versión anterior. Si no tiene MacPorts instalado, hay un ejemplo de configuración de instalación para hacer esto en esta página. ¡Sí! Necesitará todas las herramientas de desarrollo de xcode, ya que estos métodos le "construirán" un GTKWave desde la fuente.
Cuando finaliza la instalación, se le puede solicitar que seleccione una versión de python. Ya tenía 2.7.10 instalado, así que nunca "seleccioné" uno nuevo.
En este punto, puede iniciar gtkwave desde la línea de comandos con gtkwave
. Cuando comience, se le puede pedir que instale o actualice XQuarts. Hazlo En mi caso XQuarts 2.7.11 está instalado.
Nota: en realidad necesitaba reiniciar para obtener XQuarts correctamente, luego tecleé gtkwave
nuevo y aparece la aplicación.
En el siguiente ejemplo, crearé dos archivos independientes, un banco de pruebas y un módulo para probar, y usaremos gtkwave para ver el diseño.
Uso de Icarus Verilog y GTKWaves para simular y ver gráficamente un diseño
Este ejemplo utiliza Icarus y GTKWave. Las instrucciones de instalación para esas herramientas en OSx se proporcionan en otra parte de esta página.
Comencemos con el diseño del módulo. Este módulo es una pantalla de BCD a 7 segmentos. He codificado el diseño de una manera obtusa simplemente para darnos algo que se rompe fácilmente y podemos dedicar algún tiempo a arreglarlo gráficamente. Así que tenemos un reloj, reinicio, una entrada de 4 datos que representa un valor BCD y una salida de 7 bits que representa la pantalla de siete segmentos. Cree un archivo llamado bcd_to_7seg.v y coloque la fuente a continuación.
module bcd_to_7seg (
input clk,
input reset,
input [3:0] bcd,
output [6:0] seven_seg_display
);
parameter TP = 1;
reg seg_a;
reg seg_b;
reg seg_c;
reg seg_d;
reg seg_e;
reg seg_f;
reg seg_g;
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
seg_a <= #TP 1'b0;
seg_b <= #TP 1'b0;
seg_c <= #TP 1'b0;
seg_d <= #TP 1'b0;
seg_e <= #TP 1'b0;
seg_f <= #TP 1'b0;
seg_g <= #TP 1'b0;
end
else
begin
seg_a <= #TP ~(bcd == 4'h1 || bcd == 4'h4);
seg_b <= #TP bcd < 4'h5 || bcd > 6;
seg_c <= #TP bcd != 2;
seg_d <= #TP bcd == 0 || bcd[3:1] == 3'b001 || bcd == 5 || bcd == 6 || bcd == 8;
seg_e <= #TP bcd == 0 || bcd == 2 || bcd == 6 || bcd == 8;
seg_f <= #TP bcd == 0 || bcd == 4 || bcd == 5 || bcd == 6 || bcd > 7;
seg_g <= #TP (bcd > 1 && bcd < 7) || (bcd > 7);
end
end
assign seven_seg_display = {seg_g,seg_f,seg_e,seg_d,seg_c,seg_b,seg_a};
endmodule
A continuación, necesitamos una prueba para verificar si este módulo está funcionando correctamente. En mi opinión, la declaración del caso en el banco de pruebas es más fácil de leer y más clara en cuanto a lo que hace. Pero no quise poner la misma declaración de caso en el diseño Y en la prueba. Esa es una mala práctica. Más bien, se están utilizando dos diseños independientes para validar uno a otro.
Dentro del código a continuación, notará dos líneas $dumpfile("testbench.vcd");
y $dumpvars(0,testbench);
. Estas líneas son las que crean el archivo de salida VCD que se utilizará para realizar un análisis gráfico del diseño. Si los deja afuera, no obtendrá un archivo VCD generado. Cree un archivo llamado testbench.v y coloque la fuente debajo en él.
`timescale 1ns/100ps
module testbench;
reg clk;
reg reset;
reg [31:0] ii;
reg [31:0] error_count;
reg [3:0] bcd;
wire [6:0] seven_seg_display;
parameter TP = 1;
parameter CLK_HALF_PERIOD = 5;
// assign clk = #CLK_HALF_PERIOD ~clk; // Create a clock with a period of ten ns
initial
begin
clk = 0;
#5;
forever clk = #( CLK_HALF_PERIOD ) ~clk;
end
initial
begin
$dumpfile("testbench.vcd");
$dumpvars(0,testbench);
// clk = #CLK_HALF_PERIOD ~clk;
$display("%0t, Reseting system", $time);
error_count = 0;
bcd = 4'h0;
reset = #TP 1'b1;
repeat (30) @ (posedge clk);
reset = #TP 1'b0;
repeat (30) @ (posedge clk);
$display("%0t, Begin BCD test", $time); // This displays a message
for (ii = 0; ii < 10; ii = ii + 1)
begin
repeat (1) @ (posedge clk);
bcd = ii[3:0];
repeat (1) @ (posedge clk);
if (seven_seg_display !== seven_seg_prediction(bcd))
begin
$display("%0t, ERROR: For BCD %d, module output 0b%07b does not match prediction logic value of 0b%07b.",$time,bcd, seven_seg_display,seven_seg_prediction(bcd));
error_count = error_count + 1;
end
end
$display("%0t, Test Complete with %d errors", $time, error_count);
$display("%0t, Test %s", $time, ~|error_count ? "pass." : "fail.");
$finish ; // This causes the simulation to end.
end
parameter SEG_A = 7'b0000001;
parameter SEG_B = 7'b0000010;
parameter SEG_C = 7'b0000100;
parameter SEG_D = 7'b0001000;
parameter SEG_E = 7'b0010000;
parameter SEG_F = 7'b0100000;
parameter SEG_G = 7'b1000000;
function [6:0] seven_seg_prediction;
input [3:0] bcd_in;
// +--- A ---+
// | |
// F B
// | |
// +--- G ---+
// | |
// E C
// | |
// +--- D ---+
begin
case (bcd_in)
4'h0: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
4'h1: seven_seg_prediction = SEG_B | SEG_C;
4'h2: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
4'h3: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D;
4'h4: seven_seg_prediction = SEG_F | SEG_G | SEG_B | SEG_C;
4'h5: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
4'h6: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D;
4'h7: seven_seg_prediction = SEG_A | SEG_B | SEG_C;
4'h8: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
4'h9: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_B | SEG_C;
default: seven_seg_prediction = 7'h0;
endcase
end
endfunction
bcd_to_7seg u0_bcd_to_7seg (
.clk (clk),
.reset (reset),
.bcd (bcd),
.seven_seg_display (seven_seg_display)
);
endmodule
Ahora que tenemos dos archivos, un testbench.v y bcd_to_7seg.v, necesitamos compilar, elaborar utilizando Icarus. Para hacer esto:
$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
A continuación necesitamos simular
$ vvp testbench.vvp
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
8000, Test Complete with 0 errors
8000, Test pass.
En este punto, si desea validar, el archivo realmente se está probando, vaya al archivo bcd_2_7seg.v, mueva parte de la lógica y repita esos dos primeros pasos.
Como ejemplo, cambio la línea seg_c <= #TP bcd != 2;
a seg_c <= #TP bcd != 4;
. Recompila y simula lo siguiente:
$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
$ vvp testbench.vvp
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
6600, ERROR: For BCD 2, module output 0b1011111 does not match prediction logic value of 0b1011011.
7000, ERROR: For BCD 4, module output 0b1100010 does not match prediction logic value of 0b1100110.
8000, Test Complete with 2 errors
8000, Test fail.
$
Así que ahora, veamos la simulación usando GTKWave. Desde la línea de comando, emita un
gtkwave testbench.vcd &
Cuando aparezca la ventana de GTKWave, verá en la casilla superior izquierda, el nombre del módulo testbench. Pinchalo. Esto revelará los submódulos, tareas y funciones asociadas con ese archivo. Los cables y registros también aparecerán en la casilla inferior izquierda.
Ahora arrastre, clk, bcd, error_count y seven_seg_display en el cuadro de señal al lado de la ventana de forma de onda. Las señales ahora serán trazadas. Error_count le mostrará qué entrada de BCD en particular generó la salida de seven_seg_display incorrecta.
Ahora está listo para solucionar un error de Verilog gráficamente.