vhdl
D-Flip-Flops (DFF) y cierres
Buscar..
Observaciones
Los D-Flip-Flops (DFF) y los pestillos son elementos de memoria. Un DFF muestra su entrada en uno u otro borde de su reloj (no en ambos) mientras que un pestillo es transparente en un nivel de su habilitación y memoriza en el otro. La siguiente figura ilustra la diferencia:
Modelar DFFs o pestillos en VHDL es fácil, pero hay algunos aspectos importantes que deben tenerse en cuenta:
Las diferencias entre los modelos VHDL de DFFs y latches.
Cómo describir los bordes de una señal.
Cómo describir conjuntos o reinicios síncronos o asíncronos.
D-Flip-Flops (DFF)
En todos los ejemplos:
-
clk
es el reloj, -
d
es la entrada, -
q
es la salida, -
srst
es un reinicio alto síncrono activo, -
srstn
es un reinicio bajo sincronizado activo, -
arst
es un alto reinicio asíncrono activo, -
arstn
es un restablecimiento asíncrono bajo activo, -
sset
es un conjunto alto síncrono activo, -
ssetn
es un conjunto sincrónico bajo activo, -
aset
es un conjunto alto asíncrono activo, -
asetn
es un conjunto asíncrono bajo activo.
Todas las señales son de tipo ieee.std_logic_1164.std_ulogic
. La sintaxis utilizada es la que lleva a corregir los resultados de síntesis con todos los sintetizadores lógicos. Consulte el ejemplo de detección del borde del reloj para ver una discusión sobre la sintaxis alternativa.
Reloj de vanguardia
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
Reloj de borde descendente
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
Reloj de flanco ascendente, reinicio alto activo síncrono
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Reloj de flanco ascendente, alto reinicio activo asíncrono
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Falling edge clock, restablecimiento activo bajo asíncrono, ajuste alto activo síncrono
process(clk, arstn)
begin
if arstn = '0' then
q <= '0';
elsif falling_edge(clk) then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
Reloj de flanco ascendente, reinicio alto activo asíncrono, conjunto bajo activo asíncrono
Nota: el conjunto tiene mayor prioridad que el reinicio
process(clk, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Pestillos
En todos los ejemplos:
-
en
está como señal de activación, -
d
es la entrada, -
q
es la salida, -
srst
es un reinicio alto síncrono activo, -
srstn
es un reinicio bajo sincronizado activo, -
arst
es un alto reinicio asíncrono activo, -
arstn
es un restablecimiento asíncrono bajo activo, -
sset
es un conjunto alto síncrono activo, -
ssetn
es un conjunto sincrónico bajo activo, -
aset
es un conjunto alto asíncrono activo, -
asetn
es un conjunto asíncrono bajo activo.
Todas las señales son de tipo ieee.std_logic_1164.std_ulogic
. La sintaxis utilizada es la que lleva a corregir los resultados de síntesis con todos los sintetizadores lógicos. Consulte el ejemplo de detección del borde del reloj para ver una discusión sobre la sintaxis alternativa.
Alta habilitación activa
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
Activación baja activa
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
Activación alta activa, reinicio alto síncrono activo
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Activación alta activa, reinicio alto asíncrono activo
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Activación baja activa, reinicio bajo asíncrono activo, ajuste alto activo síncrono
process(en, d, arstn)
begin
if arstn = '0' then
q <= '0';
elsif en = '0' then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
Activación alta activa, reinicio alto activo asíncrono, conjunto bajo activo asíncrono
Nota: el conjunto tiene mayor prioridad que el reinicio
process(en, d, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Detección del borde del reloj
La historia corta
Con VHDL 2008 y si el tipo de reloj es bit
, boolean
, ieee.std_logic_1164.std_ulogic
o ieee.std_logic_1164.std_logic
, se puede codificar una detección de borde de reloj para borde ascendente
-
if rising_edge(clock) then
-
if clock'event and clock = '1' then -- type bit, std_ulogic or std_logic
-
if clock'event and clock then -- type boolean
y para caer al filo
-
if falling_edge(clock) then
-
if clock'event and clock = '0' then -- type bit, std_ulogic or std_logic
-
if clock'event and not clock then -- type boolean
Esto se comportará como se espera, tanto para la simulación como para la síntesis.
Nota: la definición de un flanco ascendente en una señal de tipo
std_ulogic
es un poco más compleja que la simpleif clock'event and clock = '1' then
. La función estándarrising_edge
, por ejemplo, tiene una definición diferente. Incluso si probablemente no hará ninguna diferencia para la síntesis, podría hacer uno para la simulación.
Se recomienda rising_edge
el uso de las funciones estándar rising_edge
y falling_edge
. Con versiones anteriores de VHDL, el uso de estas funciones puede requerir declarar explícitamente el uso de paquetes estándar (por ejemplo, ieee.numeric_bit
para el tipo de bit
) o incluso definirlos en un paquete personalizado.
Nota: no utilice las funciones estándar
rising_edge
yfalling_edge
para detectar bordes de señales que no sean de reloj. Algunos sintetizadores podrían concluir que la señal es un reloj. Sugerencia: la detección de un borde en una señal que no es de reloj se puede hacer frecuentemente muestreando la señal en un registro de desplazamiento y comparando los valores muestreados en diferentes etapas del registro de desplazamiento.
La larga historia
La descripción correcta de la detección de los bordes de una señal de reloj es esencial al modelar D-Flip-Flops (DFF). Un borde es, por definición, una transición de un valor particular a otro. Por ejemplo, podemos definir el flanco ascendente de una señal de tipo bit
(el tipo enumerado VHDL estándar que toma dos valores: '0'
y '1'
) como la transición de '0'
a '1'
. Para el tipo boolean
podemos definirlo como una transición de false
a true
.
Con frecuencia, se utilizan tipos más complejos. El tipo ieee.std_logic_1164.std_ulogic
, por ejemplo, también es un tipo enumerado, como bit
o boolean
, pero tiene 9 valores en lugar de 2:
Valor | Sentido |
---|---|
'U' | Sin inicializar |
'X' | Forzando desconocido |
'0' | Forzando bajo nivel |
'1' | Forzando alto nivel |
'Z' | Alta impedancia |
'W' | Débil desconocido |
'L' | Débil bajo nivel |
'H' | Débil alto nivel |
'-' | No importa |
Definir un flanco ascendente en un tipo de este tipo es un poco más complejo que para bit
o boolean
. Podemos, por ejemplo, decidir que es una transición de '0'
a '1'
. Pero también podemos decidir que es una transición de '0'
o 'L'
a '1'
o 'H'
.
Nota: esta es la segunda definición que usa el estándar para la función
rising_edge(signal s: std_ulogic)
definida enieee.std_logic_1164
.
Cuando se analizan las diversas formas de detectar bordes, es importante considerar el tipo de señal. También es importante tener en cuenta el objetivo de modelado: ¿solo simulación o síntesis lógica? Vamos a ilustrar esto con algunos ejemplos:
Flanco DFF con bit de tipo
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
Técnicamente, en un punto de vista semántico de simulación puro, el proceso P1
modela un DFF de flanco ascendente. De hecho, la asignación q <= d
se ejecuta si y solo si:
-
clock
cambiado (esto es lo que expresa la lista de sensibilidad) y - El valor actual del
clock
es'1'
.
Como el clock
es de tipo bit y tipo bit solo tiene valores '0'
y '1'
, esto es exactamente lo que definimos como un flanco ascendente de una señal de tipo bit. Cualquier simulador manejará este modelo como esperamos.
Nota: para los sintetizadores lógicos, las cosas son un poco más complejas, como veremos más adelante.
DFF de flanco ascendente con restablecimiento alto activo asíncrono y bit de tipo
Para agregar un restablecimiento alto activo asíncrono a nuestro DFF, se podría intentar algo como:
signal clock, reset, d, q: bit;
...
P2_BOGUS: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' then
q <= d;
end if;
end process P2_BOGUS;
Pero esto no funciona . La condición para que se ejecute la asignación q <= d
debe ser: un flanco ascendente del clock
mientras se reset = '0'
. Pero lo que modelamos es:
-
clock
oreset
o ambos cambiados y -
reset = '0'
y -
clock = '1'
Que no es lo mismo: si reset
cambia de '1'
a '0'
, mientras que clock = '1'
la asignación se ejecutarán si bien no es un flanco ascendente de clock
.
De hecho, no hay forma de modelar esto en VHDL sin la ayuda de un atributo de señal:
P2_OK: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' and clock'event then
q <= d;
end if;
end process P2_OK;
El clock'event
es el event
atributo de señal aplicado al clock
señal. Se evalúa como un valor boolean
y es true
si y solo si el clock
señal cambió durante la fase de actualización de la señal que precedió a la fase de ejecución actual. Gracias a esto, el proceso P2_OK
ahora modela perfectamente lo que queremos en simulación (y síntesis).
Semántica de síntesis
Muchos sintetizadores lógicos identifican detecciones de borde de señal basadas en patrones sintácticos, no en la semántica del modelo VHDL. En otras palabras, consideran cómo se ve el código VHDL, no qué comportamiento modela. Uno de los patrones que todos reconocen es:
if clock = '1' and clock'event then
Entonces, incluso en el ejemplo del proceso P1
, deberíamos usarlo si queremos que nuestro sintetizador sea sintetizable por todos los sintetizadores lógicos:
signal clock, d, q: bit;
...
P1_OK: process(clock)
begin
if clock = '1' and clock'event then
q <= d;
end if;
end process P1_OK;
La parte de la condición de " and clock'event
es completamente redundante con la lista de sensibilidad, pero como algunos sintetizadores lo necesitan ...
DFF de flanco ascendente con restablecimiento alto activo asíncrono y tipo std_ulogic
En este caso, la expresión del flanco ascendente del reloj y la condición de restablecimiento puede complicarse. Si mantenemos la definición de un flanco ascendente que propusimos anteriormente y si consideramos que el restablecimiento está activo si es '1'
o 'H'
, el modelo se convierte en:
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4: process(clock, reset)
begin
if reset = '1' or reset = 'H' then
q <= '0';
elsif clock'event and
(clock'last_value = '0' or clock'last_value = 'L') and
(clock = '1' or clock = 'H') then
q <= d;
end if;
end process P4;
Nota:
'last_value
es otro atributo de señal que devuelve el valor que tenía la señal antes del último cambio de valor.
Funciones de ayuda
El estándar VHDL 2008 ofrece varias funciones de ayuda para simplificar la detección de bordes de señal, especialmente con tipos enumerados de valores múltiples como std_ulogic
. El paquete std.standard
define las funciones rising_edge
y falling_edge
en los tipos bit
y boolean
y el paquete ieee.std_logic_1164
las define en los tipos std_ulogic
y std_logic
.
Nota: con versiones anteriores de VHDL, el uso de estas funciones puede requerir declarar explícitamente el uso de paquetes estándar (por ejemplo, ieee.numeric_bit para el tipo de bit) o incluso definirlos en un paquete de usuario.
Revisemos los ejemplos anteriores y usemos las funciones de ayuda:
signal clock, d, q: bit;
...
P1_OK_NEW: process(clock)
begin
if rising_edge(clock) then
q <= d;
end if;
end process P1_OK_NEW;
signal clock, d, q: bit;
...
P2_OK_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P2_OK_NEW;
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P4_NEW;
Nota: en este último ejemplo también simplificamos la prueba en el reinicio. Los reinicios flotantes, de alta impedancia son bastante raros y, en la mayoría de los casos, esta versión simplificada funciona para simulación y síntesis.