En concreto, Verilog es un lenguaje de descripción de hardware (HDL: Hardware Description Language), creado en 1983 en la compañía Automated Integrated Design Systems. Verilog está estandarizado por el IEEE. Los HDLs permiten describir un diseño al nivel de transferencia entre registros. Los detalles de más bajo nivel (puertas lógicas y su interconexión) pueden ser generadas por herramientas automáticas de síntesis a partir de su descripción en un HDL. Los HDLs también se pueden usar para simular y depurar el resultado obtenido, por lo que la elaboración de hardware sigue un proceso en la actualidad que coincide en muchos aspectos con la elaboración de software.
La sintaxis de Verilog es muy similar a la sintaxis de C, por lo que estas prácticas os servirán de apoyo y complemento a las realizadas en las asignaturas de programación.
Icarus Verilog y GPL Cver son dos implementaciones de Verilog libres que están disponibles para Linux.
Si os instaláis una distribución de Linux
basada en Debian (la propia Debian, u otras más
sencillas como Kubuntu), debéis instalar los
paquetes iverilog
y/o gplcver
:
sudo apt-get install iverilog sudo apt-get install gplcver
En los ordenadores de clase, ya están instalados estos dos paquetes.
Se necesita, tambíen, un editor de texto para
generar los programas. Cualquiera que genere texto
plano puede ser válido: vi
,
kate
, gedit
, etc.
Abrid, pues, el editor de textos para generar el siguiente
fichero al que nombraréis hello.v
:
/* Programa de ejemplo: hello.v */ module hello; initial // Imprimimos el mensaje y un salto de lInea $display("Hola, mundo\n"); endmodule
Una vez hayáis guardado el programa, debéis
abrir una ventana con la línea de órdenes.
Observad que habéis creado bien el programa tecleando
ls -l
. Os ha de aparecer una línea
similar a la siguiente:
-rw-r--r-- 1 gyermo gyermo 151 2010-05-20 20:50 hello.v
Procedamos ahora a compilar y ejecutar el programa:
iverilog hello.v -o helloDebe aparecer ahora un fichero ejecutable, cuyo nombre será
hello
. Miradlo con ls -l
:
-rwxr-xr-x 1 gyermo gyermo 448 2010-05-20 20:50 hello -rw-r--r-- 1 gyermo gyermo 151 2010-05-20 20:50 hello.vFinalmente, lo ejecutamos con
./hello
:
Hola, mundo
cver
no es necesario compilar. Simplemente
hay que teclear cver hello.v
. La salida es:
GPLCVER_2.12a of 05/16/07 (Linux-elf). Copyright (c) 1991-2007 Pragmatic C Software Corp. All Rights reserved. Licensed under the GNU General Public License (GPL). See the 'COPYING' file for details. NO WARRANTY provided. Today is Thu May 20 21:39:01 2010. Compiling source file "hello.v" Highest level modules: hello Hola, mundo 0 simulation events and 0 declarative immediate assigns processed. 1 behavioral statements executed (1 procedural suspends). Times (in sec.): Translate 0.0, load/optimize 0.1, simulation 0.1. End of GPLCVER_2.12a at Thu May 20 21:39:01 2010 (elapsed 0.0 seconds).Esta salida también se escribe en un fichero denominado
verilog.log
. Lo podéis comprobar tecleando
cat verilog.log
.
De ahora en adelante, podéis usar cualquiera de los
dos, iverilog
o cver
, a no ser que
se especifique lo contrario en algún apartado.
/* Este es un tipo de comentario */ /* Este tipo de comentario puede abarcar varias lIneas */ // Este tipo de comentario sOlo puede abarcar una lInea
\n | retorno del carro |
\t | tabulador |
%% | % |
\\ | \ |
\" | " |
\xxx | cualquier carácter, xxx en octal |
"Hola, mundo\n"
es un ejemplo de una cadena
de caracteres que tiene 12 caracteres: 4 caracteres de la palabra
Hola, una coma, un espacio, 5 caracteres de la palabra
mundo y un carácter especial que hace que se produzca
un salto a la línea siguiente (\n
).
'b
(binario),
'o
(octal),
'd
(el propio decimal)
'h
(hexadecimal).
Si el número es negativo, se antepone el signo menos.
Por ejemplo, -'hD1C
.
Los números reales se pueden expresar en la notación
habitual, usando el punto como separador decimal o en notación
científica (por ejemplo, 7.237e10
).
Solamente se admite
la base 10 en los números reales.
Con el objetivo de aumentar la legibilidad de los números
binarios, se permite el uso del carácter de subrayado
dentro de una constante numérica. Por ejemplo,
'b1_1011_1111_1000
es lo mismo que
'b1101111111000
.
integer
) y
otro un número de coma flotante (real
).
El entero será del tamaño de la palabra que maneje nuestro ordenador, pero, como mínimo de 32 bits.
for
,
if
o while
admiten en su cuerpo
una única instrucción o varias (un bloque
de instrucciones). En C, estos bloques se encierran entre
llaves ({
y }
). En Verilog, esta
misma función la realizan las palabras reservadas
begin
y end
.
Así, la instrucción initial
del ejemplo hello.v
solo tienen una instrucción
$display
en su cuerpo. No necesita, por tanto,
ni begin
ni end
. Si llevara más
instrucciones sí que sería necesario, como en el ejemplo
del apartado siguiente.
$display
$display
puede llevar un número
arbitrario de argumentos y no devuelve nada. Sirve para sacar información
por la pantalla. Si no lleva argumentos, imprime un salto de
línea. De llevarlos, el primero es una cadena de caracteres que,
como en el caso de hello.v
, se imprimirá en la
pantalla.
$display
puede también imprimir
en la pantalla el contenido de las variables que deseemos imprimir.
Para ello, se incluye un códigos de formato en el lugar que
queremos que aparezca el contenido de la variable. El código
de formato también sirve para indicar en qué base, por
ejemplo, queremos que salga el valor. Cuando se incluyen códigos
de formato, hay que añadir un parámetro por cada uno
de ellos indicando la variable cuyo contenido deseamos imprimir.
Por ejemplo:
integer i; real f; initial begin i=4; f=2.7172; $display("i vale %d y f vale %g",i,f); endLa salida de este programa debería ser:
i vale 4 y f vale 2.7172
$display
ha sustituido el primer %d
por
el contenido del la variable que aparece en el segundo argumento
(la i
) y %f
por el contenido de la
variable que aparece como tercer argumento (j
).
Los códigos de formato de $display
aparecen
a continuación. Son también admisibles con
mayúscula, con el mismo significado.
%d | Entero en decimal |
%b | Entero en binario |
%o | Entero en octal |
%h | Entero en hexadecimal |
%c | Carácter |
%s | Cadena de caracteres |
%f | Real en formato decimal |
%e | Real en formato científico |
%g | Real en el formato más corto de los dos anteriores |
ej_1_9
i
y f
en las dos que aparecen en el ejemplo) y son de
una clase (técnicamente tienen un tipo). El tipo
de variable nos indica la clase de valores que puede contener
la variable. En el ejemplo, la primera variable puede contener
enteros (integer
) y la segunda variable, números
de coma flotante (real
). En el área marcada
se definirán las variables que vamos a usar en el móduloinitial
: dentro de este bloque
situaremos las instrucciones del módulo (el programa).
Las instrucciones se irán ejecutando una tras otra.
Si el bloque contuviera una única instrucción, como
en el primer ejemplo (hello.v
), no sería necesario
incluir las palabras begin
y end
. En el
resto de casos se incluyen para que el ordenador sepa dónde
empieza y acaba el bloquei
y j
y, posteriormente,
imprimimos el contenido de las variables con la función
$display
.endmodule
module
, las declaraciones de variables
y las órdenes de nuestro programa deben acabar
obligatoriamente en punto y coma (;
)signed
, como
se muestra en los siguientes ejemplos:
reg reloj; /* Registro de un bit */ reg [31:0] busA; /* Registro de 32 bits, sin signo */ reg signed [63:0] m; /* Registro de 64 bits, con signo */Al asignarle un valor a un registro, podemos hacerlo al completo o a un subconjunto de sus bits. Si lo que se asigna es una constante, se le puede anteponer su tamaño en bits:
reloj=1'b0; busA='hAAAABBBB; busA[7:4]=4'hC; m=-1;
+
), resta (-
),
multiplicación (*
) y
división (/
). También existe un
operador de exponenciación que no existe en C
(**
).
La división de dos cantidades enteras nos da
la parte entera del cociente. Si se quiere saber cuál
es el resto de la división, se debe usar el
operador módulo (%
).
$display
los cuatro dígitos hexadecimales
que forman el registro, empezando por el menos significativo.
Por ejemplo, si asignáis a la variable
'hAB12
, debe salir por la pantalla 2, 1,
b y a.
>>
)<<
)>>>
)<<<
)LOGICAL
SHIFT RIGHT (con signo o sin signo) |
1011101010101011 |
>>
7 |
0000000101110101 |
ARITHMETIC
SHIFT RIGHT (con signo) |
1011101010101011 |
>>>
7 |
1111111101110101 |
ARITHMETIC
SHIFT RIGHT (sin signo) |
1011101010101011 |
>>>
7 |
0000000101110101 |
El primer operando es el número que se quiere desplazar y
el segundo indica el número de bits, como en este ejemplo
en que se desplaza 3 posiciones a la izquierda el contenido del
registro a
y el resultado se escribe en b
:
b= (a<<3);
pos
y neg
, y dadles
un valor inicial positivo al primero y negativo al segundo.
Efectuad los cuatro tipos de desplazamientos sobre los números
originales y anotad el resultado. Debéis imprimir los
números en binario y decimal. Los desplazamientos serán
todos de un bit. Se debe restaurar el valor de pos
y neg
después de cada desplazamiento.
Estas variables se usan como los cables en la realidad: para conectar puertas o módulos entre sí. Su tamaño es, por defecto, de un bit.
Necesitan que algún otro elemento les esté proporcionando su valor, al contrario que los registros, que son capaces de almacenarlo.
x
y significa que el valor puede ser cero o uno, no
se sabez
y tiene el significado habitual en
electrónica
Tanto x
como z
funcionan como
dígitos normales. Por ejemplo, el valor
'b11xxzz00
indica que los primeros
dos bits son 1, los dos siguientes no se sabe, los dos
siguientes están en alta impedancia y los
dos últimos son 0.
Si al asignar un valor en un programa a un registro, el
valor especificado es de menos bits que el registro, se asigna
valor a esos bits con la siguiente regla: si el valor especificado
tiene el bit
más significativo a 1 ó 0, los bits más
significativos asignados son 0. Si dicho bit es x
,
son x
. Y, si es z
, son z
.
x
y los últimos
cuatro z
. Imprimid en binario
el valor del registro. Realizad operaciones
con él y observad el resultado.
ls
cd
rm
man
cat