Mediante puertas
Partimos del diseño que se ha visto en teoría, que
es un biestable activo por nivel alto:
Para convertirlo en uno activo por flanco de subida de reloj, usamos un
adaptador como el visto en la sesión anterior:
Pero el enunciado nos pide construir un biestable activo por
flanco de bajada del reloj. Las maneras de obtenerlo
son múltiples. La más sencilla es añadir
a la entrada de reloj simplemente una puerta NOT, con lo que
los flancos se invierten y hemos logrado el objetivo.
Sin embargo, vamos a modificar ligeramente los diseños
para lograr el mismo objetivo. Primero modificamos ligeramente
el diseño original del biestable para que sea activo por
nivel bajo. Es muy fácil darse cuenta que cambiando
la localización de la puerta NOT del diseño primero
el biestable realimenta el contenido cuando C está alto
y permite pasar el dato cuando C está bajo. Justo lo que
queremos:
Para transformar, ahora el biestable activo por nivel bajo en uno
activo por flanco de bajada, no hay más que cambiar la
puerta AND del adaptador anterior por una puerta OR:
Comencemos la construcción del biestable activo por nivel bajo:
Con todo lo visto anteriormente, podemos construir los
módulos Ddown
(biestable D activo por nivel
bajo), Detector
(detector de flanco de bajada
para circuito activo por nivel bajo), Ddownedge
(biestable D activo por flanco de bajada, que es el activo
por nivel con el detector de flanco antepuesto a su entrada
de reloj) y TestDdownedge
(módulo
comprobador):
module Ddown(output wire Q, input wire D, input wire C);
wire wa1, wa2;
not n(wn,C);
and a1(wa1,D,wn);
and a2(wa2,C,Q);
or o(Q,wa1,wa2);
endmodule
module Detector(output wire DET, input wire C);
wire Cnr;
not #(1) n(Cnr,C);
or o(DET,C,Cnr);
endmodule
module Ddownedge(output wire Q, input wire D, input wire C);
wire wConector;
Ddown dd(Q,D,wConector);
Detector det(wConector,C);
endmodule
module TestDdownedge;
reg rD,rC;
wire wQ;
Ddownedge dde(wQ,rD,rC);
always #7 rC= ~rC;
initial
begin
$monitor($time," C:%b DET:%b D:%b Q:%b",rC,dde.wConector,rD,wQ);
rC=0; rD=0;
#5 rD=1;
#5 rD=1;
#5 rD=0;
#5 rD=1;
#5 rD=0;
#5 rD=0;
#5 rD=0;
#5 rD=1;
#5 rD=1;
#5 rD=0;
#5 rD=1;
#5 rD=0;
#5 rD=1;
#5 rD=1;
#5 rD=0;
#5 rD=1;
$finish;
end
endmodule
La salida ofrece casi el resultado esperado: un biestable D que
reacciona a su entrada solamente cuando el reloj baja:
0 C:0 DET:x D:0 Q:x
1 C:0 DET:1 D:0 Q:x
5 C:0 DET:1 D:1 Q:x
7 C:1 DET:1 D:1 Q:x
14 C:0 DET:0 D:1 Q:1
15 C:0 DET:1 D:0 Q:0
20 C:0 DET:1 D:1 Q:0
21 C:1 DET:1 D:1 Q:0
25 C:1 DET:1 D:0 Q:0
28 C:0 DET:0 D:0 Q:0
29 C:0 DET:1 D:0 Q:0
35 C:1 DET:1 D:0 Q:0
40 C:1 DET:1 D:1 Q:0
42 C:0 DET:0 D:1 Q:1
43 C:0 DET:1 D:1 Q:1
49 C:1 DET:1 D:1 Q:1
50 C:1 DET:1 D:0 Q:1
55 C:1 DET:1 D:1 Q:1
56 C:0 DET:0 D:1 Q:1
57 C:0 DET:1 D:1 Q:1
60 C:0 DET:1 D:0 Q:1
63 C:1 DET:1 D:0 Q:1
65 C:1 DET:1 D:1 Q:1
70 C:0 DET:0 D:1 Q:1
71 C:0 DET:1 D:1 Q:1
75 C:0 DET:1 D:0 Q:1
77 C:1 DET:1 D:0 Q:1
80 C:1 DET:1 D:1 Q:1
La excepción parece estar en las líneas t=14 y t=15
(gracias a Gabriel por darse cuenta de esta circunstancia):
[...]
7 C:1 DET:1 D:1 Q:x
14 C:0 DET:0 D:1 Q:1
15 C:0 DET:1 D:0 Q:0
[...]
En el flanco de bajada del reloj de t=14 se atrapa correctamente
en la salida Q la entrada D, pero, y aquí está lo
inesperado, en t=15, se vuelve a atrapar la entrada Q de un modo
no deseado. La razón de este comportamiento extraño
se debe a que confluyen en t=15 dos cambios de señal
simultáneos: D cambia de 1 a 0 y DET cambia de 0 a 1.
Verilog considera primero el cambio de D, con lo que su cero queda
atrapado en el biestable al cambiar a continuación DET.
En un caso real no se produciría esta confluencia de cambios.
Le podemos decir a Verilog que ambas señales cambien
simultáneamente, si en lugar de usar el operador de
asignación =
, usamos
el operador de asignación no
bloqueante <=
, visto en la sesión
anterior, tanto para el reloj como para la señal de datos:
[...]
always #7 rC<= ~rC;
initial
begin
$monitor($time," C:%b DET:%b D:%b Q:%b",rC,dde.wConector,rD,wQ);
rC<=0; rD<=0;
#5 rD<=1;
#5 rD<=1;
#5 rD<=0;
#5 rD<=1;
#5 rD<=0;
#5 rD<=0;
#5 rD<=0;
#5 rD<=1;
#5 rD<=1;
#5 rD<=0;
#5 rD<=1;
#5 rD<=0;
#5 rD<=1;
#5 rD<=1;
#5 rD<=0;
#5 rD<=1;
$finish;
end
[...]
Con esta modificación, el resultado es el esperado:
0 C:0 DET:x D:0 Q:x
1 C:0 DET:1 D:0 Q:x
5 C:0 DET:1 D:1 Q:x
7 C:1 DET:1 D:1 Q:x
14 C:0 DET:0 D:1 Q:1
15 C:0 DET:1 D:0 Q:1
20 C:0 DET:1 D:1 Q:1
21 C:1 DET:1 D:1 Q:1
25 C:1 DET:1 D:0 Q:1
28 C:0 DET:0 D:0 Q:0
29 C:0 DET:1 D:0 Q:0
35 C:1 DET:1 D:0 Q:0
40 C:1 DET:1 D:1 Q:0
42 C:0 DET:0 D:1 Q:1
43 C:0 DET:1 D:1 Q:1
49 C:1 DET:1 D:1 Q:1
50 C:1 DET:1 D:0 Q:1
55 C:1 DET:1 D:1 Q:1
56 C:0 DET:0 D:1 Q:1
57 C:0 DET:1 D:1 Q:1
60 C:0 DET:1 D:0 Q:1
63 C:1 DET:1 D:0 Q:1
65 C:1 DET:1 D:1 Q:1
70 C:0 DET:0 D:1 Q:1
71 C:0 DET:1 D:1 Q:1
75 C:0 DET:1 D:0 Q:1
77 C:1 DET:1 D:0 Q:1
80 C:1 DET:1 D:1 Q:1