Diseño VLSI - Introducción a Verilog
Verilog es un LENGUAJE DE DESCRIPCIÓN DE HARDWARE (HDL). Es un lenguaje utilizado para describir un sistema digital como un conmutador de red o un microprocesador o una memoria o un flip-flop. Significa que al usar un HDL podemos describir cualquier hardware digital en cualquier nivel. Los diseños, que se describen en HDL son independientes de la tecnología, muy fáciles de diseñar y depurar, y normalmente son más útiles que los esquemas, especialmente para circuitos grandes.
Verilog admite un diseño en muchos niveles de abstracción. Los tres principales son:
- Nivel de comportamiento
- Nivel de transferencia de registro
- Nivel de puerta
Nivel de comportamiento
Este nivel describe un sistema mediante algoritmos concurrentes (Behavioural). Cada algoritmo es secuencial, lo que significa que consta de un conjunto de instrucciones que se ejecutan una a una. Las funciones, tareas y bloques son los elementos principales. No se tiene en cuenta la realización estructural del diseño.
Nivel de transferencia de registro
Los diseños que utilizan el nivel de transferencia de registros especifican las características de un circuito que utiliza operaciones y la transferencia de datos entre los registros. La definición moderna de un código RTL es "Cualquier código sintetizable se llama código RTL".
Nivel de puerta
Dentro del nivel lógico, las características de un sistema se describen mediante enlaces lógicos y sus propiedades de temporización. Todas las señales son señales discretas. Solo pueden tener valores lógicos definidos (`0 ',` 1', `X ',` Z`). Las operaciones utilizables son primitivas lógicas predefinidas (puertas básicas). El modelado a nivel de puerta puede no ser una buena idea para el diseño lógico. El código de nivel de puerta se genera utilizando herramientas como herramientas de síntesis y su lista de conexiones se utiliza para la simulación de nivel de puerta y para backend.
Fichas léxicas
Los archivos de texto de origen del idioma Verilog son un flujo de tokens léxicos. Un token consta de uno o más caracteres, y cada carácter individual está en exactamente un token.
Los tokens léxicos básicos utilizados por Verilog HDL son similares a los del lenguaje de programación C. Verilog distingue entre mayúsculas y minúsculas. Todas las palabras clave están en minúsculas.
Espacio en blanco
Los espacios en blanco pueden contener caracteres para espacios, tabulaciones, nuevas líneas y alimentaciones de formularios. Estos caracteres se ignoran excepto cuando sirven para separar tokens.
Los caracteres de espacio en blanco son espacios en blanco, tabulaciones, retornos de carro, nueva línea y alimentaciones de formulario.
Comentarios
Hay dos formas de representar los comentarios.
- 1) Los comentarios de una sola línea comienzan con el token // y terminan con el retorno de carro.
Ej .: // esta es una sintaxis de una sola línea
- 2) Los comentarios de varias líneas comienzan con el token / * y terminan con el token * /
Ej .: / * esto es sintaxis multilínea * /
Números
Puede especificar un número en formato binario, octal, decimal o hexadecimal. Los números negativos se representan en números complementarios de 2. Verilog permite enteros, números reales y números con y sin signo.
La sintaxis viene dada por - <tamaño> <radix> <valor>
El tamaño o el número sin tamaño se puede definir en <Size> y <radix> define si es binario, octal, hexadecimal o decimal.
Identificadores
Identificador es el nombre que se utiliza para definir el objeto, como una función, módulo o registro. Los identificadores deben comenzar con caracteres alfabéticos o caracteres de subrayado. Ex. A_Z, a_z, _
Los identificadores son una combinación de caracteres alfabéticos, numéricos, de subrayado y $. Pueden tener hasta 1024 caracteres.
Operadores
Los operadores son caracteres especiales que se utilizan para poner condiciones o para operar las variables. Hay uno, dos y, a veces, tres caracteres que se utilizan para realizar operaciones en variables.
Ex. >, +, ~, &! =.
Palabras clave de Verilog
Las palabras que tienen un significado especial en Verilog se denominan palabras clave Verilog. Por ejemplo, assign, case, while, wire, reg, and, or, nand y module. No deben utilizarse como identificadores. Las palabras clave de Verilog también incluyen directivas del compilador y tareas y funciones del sistema.
Modelado de nivel de puerta
Verilog tiene primitivas integradas como puertas lógicas, puertas de transmisión e interruptores. Rara vez se utilizan para trabajos de diseño, pero se utilizan en el mundo de la post síntesis para el modelado de células ASIC / FPGA.
El modelado a nivel de puerta presenta dos propiedades:
Drive strength- La fuerza de las puertas de salida se define por la fuerza del accionamiento. La salida es más fuerte si hay una conexión directa a la fuente. La fuerza disminuye si la conexión es a través de un transistor conductor y menos cuando se conecta a través de un resistivo pull-up / down. Por lo general, no se especifica la fuerza de la unidad, en cuyo caso las fortalezas se establecen por defecto en strong1 y strong0.
Delays- Si no se especifican retardos, las puertas no tienen retardos de propagación; si se especifican dos retrasos, el primero representa el retraso de subida y el segundo, el retraso de caída; si solo se especifica un retraso, ambos, subida y bajada, son iguales. Los retrasos pueden ignorarse en la síntesis.
Primitivas de puerta
Las puertas lógicas básicas que utilizan una salida y muchas entradas se utilizan en Verilog. GATE usa una de las palabras clave, y, nand, o, nor, xor, xnor para usar en Verilog para N número de entradas y 1 salida.
Example:
Module gate()
Wire ot0;
Wire ot1;
Wire ot2;
Reg in0,in1,in2,in3;
Not U1(ot0,in0);
Xor U2(ot1,in1,in2,in3);
And U3(ot2, in2,in3,in0)
Primitivas de puerta de transmisión
Las primitivas de la puerta de transmisión incluyen tanto búferes como inversores. Tienen una sola entrada y una o más salidas. En la sintaxis de instanciación de puerta que se muestra a continuación, GATE significa la palabra clave buf o NOT gate.
Ejemplo: Not, buf, bufif0, bufif1, notif0, notif1
No - n inversor de salida
Buf - n búfer de salida
Bufifo - búfer triestado, habilitación baja activa
Bufif1 - búfer triestado, habilitación alta activa
Notifo - inversor tristate, habilitación baja activa
Notif1 - inversor tristate, habilitación alta activa
Example:
Module gate()
Wire out0;
Wire out1;
Reg in0,in1;
Not U1(out0,in0);
Buf U2(out0,in0);
Tipos de datos
Conjunto de valores
Verilog consta, principalmente, de cuatro valores básicos. Todos los tipos de datos de Verilog, que se utilizan en Verilog almacenan estos valores:
0 (cero lógico o condición falsa)
1 (uno lógico o condición verdadera)
x (valor lógico desconocido)
z (estado de alta impedancia)
el uso de xyz es muy limitado para la síntesis.
Cable
Un cable se usa para representar un cable físico en un circuito y se usa para la conexión de puertas o módulos. El valor de un hilo solo se puede leer y no asignar en una función o bloque. Un cable no puede almacenar valor, pero siempre es impulsado por una declaración de asignación continua o conectando el cable a la salida de una puerta / módulo. Otros tipos específicos de cables son:
Wand (wired-AND) - aquí el valor de Wand depende del Y lógico de todos los controladores de dispositivo conectados a él.
Wor (wired-OR) - aquí el valor de Wor depende del OR lógico de todos los controladores de dispositivo conectados a él.
Tri (three-state) - aquí todos los controladores conectados a un tri deben ser z, excepto solo uno (que determina el valor de tri).
Example:
Wire [msb:lsb] wire_variable_list;
Wirec // simple wire
Wand d;
Assign d = a; // value of d is the logical AND of
Assign d = b; // a and b
Wire [9:0] A; // a cable (vector) of 10 wires.
Wand [msb:lsb] wand_variable_list;
Wor [msb:lsb] wor_variable_list;
Tri [msb:lsb] tri_variable_list;
Registrarse
Un reg (registro) es un objeto de datos, que contiene el valor de una asignación de procedimiento a la siguiente y se usa solo en diferentes funciones y bloques de procedimiento. Un reg es un Verilog simple, registro de tipo variable y no puede implicar un registro físico. En los registros de varios bits, los datos se almacenan en forma de números sin firmar y no se utiliza la extensión de signo.
Ejemplo -
reg c; // variable de registro única de 1 bit
reg [5: 0] gema; // un vector de 6 bits;
reg [6: 0] d, e; // dos variables de 7 bits
Entrada, salida, entrada
Estas palabras clave se utilizan para declarar puertos de entrada, salida y bidireccionales de una tarea o módulo. Aquí los puertos de entrada y salida, que son de tipo cable y el puerto de salida está configurado para ser de tipo cable, reg, wand, wor o tri. Siempre, el tipo de cable predeterminado es.
Example
Module sample(a, c, b, d);
Input c; // An input where wire is used.
Output a, b; // Two outputs where wire is used.
Output [2:0] d; /* A three-bit output. One must declare type in a separate statement. */
reg [1:0] a; // The above ‘a’ port is for declaration in reg.
Entero
Los enteros se utilizan en variables de propósito general. Se utilizan principalmente en bucles: índices, constantes y parámetros. Son del tipo de datos de tipo 'reg'. Almacenan datos como números con signo, mientras que los tipos de registro declarados explícitamente los almacenan como datos sin firmar. Si el número entero no está definido en el momento de la compilación, el tamaño predeterminado sería de 32 bits.
Si un entero mantiene una constante, el sintetizador los ajusta al ancho mínimo necesario en el momento de la compilación.
Example
Integer c; // single 32-bit integer
Assign a = 63; // 63 defaults to a 7-bit variable.
Supply0, Supply1
Supply0 define cables conectados a la lógica 0 (tierra) y supply1 define los cables conectados a la lógica 1 (alimentación).
Example
supply0 logic_0_wires;
supply0 gnd1; // equivalent to a wire assigned as 0
supply1 logic_1_wires;
supply1 c, s;
Hora
El tiempo es una cantidad de 64 bits que se puede utilizar junto con la tarea del sistema $ time para mantener el tiempo de simulación. El tiempo no es compatible con la síntesis y, por lo tanto, se utiliza solo con fines de simulación.
Example
time time_variable_list;
time c;
c = $time; //c = current simulation time
Parámetro
Un parámetro define una constante que se puede establecer cuando se usa un módulo, lo que permite la personalización del módulo durante el proceso de creación de instancias.
Example
Parameter add = 3’b010, sub = 2’b11;
Parameter n = 3;
Parameter [2:0] param2 = 3’b110;
reg [n-1:0] jam; /* A 3-bit register with length of n or above. */
always @(z)
y = {{(add - sub){z}};
if (z)
begin
state = param2[1];
else
state = param2[2];
end
Operadores
Operadores aritméticos
Estos operadores realizan operaciones aritméticas. Los + y −se utilizan como operadores unarios (x) o binarios (z − y).
Los operadores que se incluyen en la operación aritmética son:
+ (suma), - (resta), * (multiplicación), / (división),% (módulo)
Example -
parameter v = 5;
reg[3:0] b, d, h, i, count;
h = b + d;
i = d - v;
cnt = (cnt +1)%16; //Can count 0 thru 15.
Operadores relacionales
Estos operadores comparan dos operandos y devuelven el resultado en un solo bit, 1 o 0.
Las variables Wire y Reg son positivas. Por lo tanto (−3'd001) = = 3'd111 y (−3b001)> 3b110.
Los Operadores que se incluyen en la operación relacional son:
- == (igual a)
- ! = (no es igual a)
- > (mayor que)
- > = (mayor o igual que)
- <(menor que)
- <= (menor o igual que)
Example
if (z = = y) c = 1;
else c = 0; // Compare in 2’s compliment; d>b
reg [3:0] d,b;
if (d[3]= = b[3]) d[2:0] > b[2:0];
else b[3];
Equivalent Statement
e = (z == y);
Operadores de bits
Operadores bit a bit que están haciendo una comparación bit a bit entre dos operandos.
Los operadores que se incluyen en la operación de bits son:
- & (bit a bit AND)
- | (bit a bit o)
- ~ (bit a bit NO)
- ^ (XOR bit a bit)
- ~ ^ o ^ ~ (XNOR bit a bit)
Example
module and2 (d, b, c);
input [1:0] d, b;
output [1:0] c;
assign c = d & b;
end module
Operadores logicos
Los operadores lógicos son operadores de bits y se utilizan solo para operandos de un solo bit. Devuelven un valor de un solo bit, 0 o 1. Pueden trabajar con números enteros o grupos de bits, expresiones y tratar todos los valores distintos de cero como 1. Los operadores lógicos generalmente se usan en declaraciones condicionales ya que trabajan con expresiones.
Los operadores que se incluyen en la operación lógica son:
- ! (NO lógico)
- && (Y lógico)
- || (OR lógico)
Example
wire[7:0] a, b, c; // a, b and c are multibit variables.
reg x;
if ((a == b) && (c)) x = 1; //x = 1 if a equals b, and c is nonzero.
else x = !a; // x =0 if a is anything but zero.
Operadores de reducción
Los operadores de reducción son la forma unaria de los operadores bit a bit y operan en todos los bits de un vector de operando. Estos también devuelven un valor de un solo bit.
Los operadores que se incluyen en la operación de Reducción son:
- & (reducción Y)
- | (reducción OR)
- ~ & (reducción NAND)
- ~ | (reducción NOR)
- ^ (reducción XOR)
- ~ ^ o ^ ~ (reducción XNOR)
Example
Module chk_zero (x, z);
Input [2:0] x;
Output z;
Assign z = & x; // Reduction AND
End module
Operadores de turno
Operadores de desplazamiento, que desplazan el primer operando según el número de bits especificado por el segundo operando en la sintaxis. Los puestos vacantes se llenan con ceros para ambas direcciones, turnos a la izquierda y a la derecha (no hay extensión de señal de uso).
Los operadores que se incluyen en la operación de cambio son:
- << (desplazamiento a la izquierda)
- >> (desplazamiento a la derecha)
Example
Assign z = c << 3; /* z = c shifted left 3 bits;
Los puestos vacantes se llenan con ceros * /
Operador de concatenación
El operador de concatenación combina dos o más operandos para formar un vector más grande.
El operador incluido en la operación de concatenación es - {} (concatenación)
Example
wire [1:0] a, h; wire [2:0] x; wire [3;0] y, Z;
assign x = {1’b0, a}; // x[2] = 0, x[1] = a[1], x[0] = a[0]
assign b = {a, h}; /* b[3] = a[1], b[2] = a[0], b[1] = h[1],
b[0] = h[0] */
assign {cout, b} = x + Z; // Concatenation of a result
Operador de replicación
El operador de replicación está haciendo varias copias de un artículo.
El operador utilizado en la operación de replicación es: {n {item}} (replicación n veces de un elemento)
Example
Wire [1:0] a, f; wire [4:0] x;
Assign x = {2{1’f0}, a}; // Equivalent to x = {0,0,a }
Assign y = {2{a}, 3{f}}; //Equivalent to y = {a,a,f,f}
For synthesis, Synopsis did not like a zero replication.
For example:-
Parameter l = 5, k = 5;
Assign x = {(l-k){a}}
Operador condicional
El operador condicional sintetiza en un multiplexor. Es del mismo tipo que se utiliza en C / C ++ y evalúa una de las dos expresiones según la condición.
El operador utilizado en la operación condicional es:
(Condición)? (Resultado si la condición es verdadera) -
(resultado si la condición es falsa)
Example
Assign x = (g) ? a : b;
Assign x = (inc = = 2) ? x+1 : x-1;
/* if (inc), x = x+1, else x = x-1 */
Operandos
Literales
Los literales son operandos de valor constante que se utilizan en las expresiones de Verilog. Los dos literales de Verilog de uso común son:
String - Un operando literal de cadena es una matriz unidimensional de caracteres, que se encierran entre comillas dobles ("").
Numeric - Un operando de número constante se especifica en número binario, octal, decimal o hexadecimal.
Example
n - entero que representa el número de bits
F - uno de los cuatro posibles formatos base -
b para binario, o para octal, d para decimal, h para hexadecimal.
“time is” // string literal
267 // 32-bit decimal number
2’b01 // 2-bit binary
20’hB36F // 20-bit hexadecimal number
‘062 // 32-bit octal number
Cables, Regs y Parámetros
Los cables, las reglas y los parámetros son los tipos de datos que se utilizan como operandos en las expresiones de Verilog.
Selección de bits "x [2]" y selección de piezas "x [4: 2]"
Las selecciones de bits y las selecciones de partes se utilizan para seleccionar un bit y varios bits, respectivamente, de un vector de cable, registro o parámetro con el uso de corchetes “[]”. Las selecciones de bits y las selecciones de partes también se usan como operandos en expresiones de la misma manera que se usan sus objetos de datos principales.
Example
reg [7:0] x, y;
reg [3:0] z;
reg a;
a = x[7] & y[7]; // bit-selects
z = x[7:4] + y[3:0]; // part-selects
Llamadas a funciones
En las llamadas de función, el valor de retorno de una función se utiliza directamente en una expresión sin necesidad de asignarlo primero a un registro o cable. Simplemente coloca la llamada a la función como uno del tipo de operandos. Es necesario asegurarse de que conoce el ancho de bits del valor de retorno de la llamada a la función.
Example
Assign x = y & z & chk_yz(z, y); // chk_yz is a function
. . ./* Definition of the function */
Function chk_yz; // function definition
Input z,y;
chk_yz = y^z;
End function
Módulos
Declaración del módulo
En Verilog, un módulo es la principal entidad de diseño. Esto indica el nombre y la lista de puertos (argumentos). Las siguientes líneas que especifican el tipo de entrada / salida (entrada, salida o inout) y el ancho de cada puerto. El ancho del puerto predeterminado es de solo 1 bit. Las variables de puerto deben declararse por cable, varita ,. . ., reg. La variable de puerto predeterminada es cable. Normalmente, las entradas son cableadas porque sus datos están bloqueados fuera del módulo. Las salidas son de tipo reg si sus señales se almacenan en el interior.
Example
module sub_add(add, in1, in2, out);
input add; // defaults to wire
input [7:0] in1, in2; wire in1, in2;
output [7:0] out; reg out;
... statements ...
End module
Asignación continua
La asignación continua en un módulo se utiliza para asignar un valor a un cable, que es la asignación normal utilizada en el exterior de los bloques siempre o iniciales. Esta asignación se realiza con una declaración de asignación explícita o para asignar un valor a un cable durante su declaración. Las asignaciones continuas se ejecutan continuamente en el momento de la simulación. El orden de las sentencias de asignación no lo afecta. Si realiza algún cambio en cualquiera de las señales de entrada del lado derecho, cambiará una señal de salida del lado izquierdo.
Example
Wire [1:0] x = 2’y01; // assigned on declaration
Assign y = c | d; // using assign statement
Assign d = a & b;
/* the order of the assign statements does not matter. */
Instancias de módulo
Las declaraciones de módulo son plantillas para crear objetos reales. Los módulos se instancian dentro de otros módulos, y cada instancia crea un objeto único a partir de esa plantilla. La excepción es el módulo de nivel superior que es su propia instanciación. Los puertos del módulo deben coincidir con los definidos en la plantilla. Se especifica -
By name, utilizando un punto ".template nombre del puerto (nombre del cable conectado al puerto)". O
By position, colocando los puertos en el mismo lugar en las listas de puertos tanto de la plantilla como de la instancia.
Example
MODULE DEFINITION
Module and4 (x, y, z);
Input [3:0] x, y;
Output [3:0] z;
Assign z = x | y;
End module