$monitor($time," R=%b, S=%b, Q=%b, NQ=%b", R, S, Q, NQ); R=0; S=0; #5 R=0; S=1; #5 R=0; S=0; #5 R=1; S=0; #5 R=1; S=1; #5 R=0; S=0; #5 R=1; S=1; #5 S=0; R=0;¿Por qué la salida es diferente en la última línea y en la antepenúltima?
#5 R=0; S=0;primero calcula el resultado de asignar 0 a R y sus consecuencias y, posteriormente, asigna 0 a S.
Existe otro tipo de asignación en Verilog, la
asignación no bloqueante. Su símbolo es
<=
. Si se usa la asignación no bloqueante,
#5 R<=0; S<=0;se asignan todos los valores y se calcula a la vez las consecuencias. Probad si se producen cambios al sustituir alguna de las asignaciones del ejercicio anterior por asignaciones no bloqueantes. Incidid especialmente en los alrededores y en los propios estados inválidos y neutros.
¿Cuál es el valor de a
, b
,
c
y d
al final del siguiente ejemplo?
#5 a=1; b=2; c=3; d=4; #5 a=b; b=a; #5 c<=d; d<=c;
always
always
da instrucciones a Verilog para
que el código que se especifica se ejecute una y otra vez
mientras dure la simulación. Podemos usar un bloque
always
para construir una señal de reloj:
always #7 C=~C;Suponemos que para generar la señal de reloj hemos definido previamente un registro
C
. El bloque always
anterior hace que dicho registro cambie a su valor complementario
cada 7 unidades de tiempo. Hemos conseguido, pues, un reloj de
periodo 14 unidades de tiempo.
always
es un bloque, del mismo tipo que el que
ya hemos visto de initial
. Si tiene que contener
más de una instrucción, deben ir rodeadas por
begin
y end
, como de costumbre.
always
a las pruebas del
ejercicio anterior para generar una señal de reloj de
periodo 14 unidades de tiempo. Obsérvese cómo
el biestable solamente reacciona a las señales R y S
cuando el reloj se encuentra en alto.
Compruébese cómo el biestable es ahora activo en los flancos de subida del reloj.
case
if
s cuando se tiene que elegir una opción
de varias en función del valor de una variable o
expresión. Su forma general es:case (
expresión)
:
instrucción primera;
:
instrucción segunda;
default:
instrucción por defecto (opcional);
endcase
case
(¡ojo! el
endcase
se deja igual) por casex
o
casez
significa que las equis o zetas han de considerarse
como comodines: casan con cualquier otro valor.
always
condicionadoalways
el nombre de una señal
de modo que el bloque se ejecute siempre que esa señal cambie:
always @(variable) begin ... endTambién se puede especificar más de una señal, separadas por comas, con el significado de que se ejecute el bloque siempre que cambie alguna de esas señales:
always @(variable1,variable2, ...) begin ... endFinalmente, añadiendo delante del nombre de la variable las palabras
posedge
o negedge
, logramos que el bloque se ejecute
en el flanco de subida o de bajada, respectivamente.
Hay veces en que no nos interesa llegar hasta tanto nivel de detalle, sino describir someramente lo que queremos y que sea una herramienta automática de síntesis la que se encargue de considerar el bajo nivel. Aparecen así los modelos de comportamiento en Verilog. Veamos cómo construimos un biestable JK activo en flanco ascendente de reloj con línea de PRESET y CLEAR, ambas activas a nivel bajo y prioritarias:
module JKup(output reg Q, output wire NQ, input wire J, input wire K, input wire C, input wire nPRESET, input wire nCLEAR); not(NQ,Q); initial begin Q=0; end always @(posedge C) if (nPRESET && nCLEAR) // PRESET y CLEAR tienen prioridad case ({J,K}) 2'b10: Q=1; 2'b01: Q=0; 2'b11: Q=~Q; endcase always @(nPRESET,nCLEAR) case ({nPRESET,nCLEAR}) // Si estAn activas ambas, no hacer nada 2'b01: Q=1; 2'b10: Q=0; endcase endmoduleLo primero que necesitamos es algo que retenga el valor de Q, por lo que transformamos el cable en un registro. Mediante una puerta NOT obtenemos el valor de NQ como hacíamos antes.
En el bloque initial
, asignamos al biestable el
valor 0
A continuación vienen dos bloques que se estarán
ejecutando siempre (always
) que se cumpla una
condición. El el primero de ellos, en el flanco de subida
de C
. El segundo, cada vez que varíen
nPRESET
o nCLEAR
.
El resto del código es bastante autoexplicativo.
Mediante el operador de concatenación ({}
),
construimos valores J,K o nPRESET,nCLEAR. Mediante la
instrucción de Verilog case
, decimos lo que
ha de suceder en los casos en que ha de suceder algo.
ls
cd
rm
man
cat