El proceso VHDL requiere múltiples ciclos de reloj

Escribí un contador simple en VHDL para un contador de programa. Todo se hace en un proceso, pero lo que no entiendo es que en la simulación, la adición del contador del programa solo se realiza en el siguiente evento del reloj, en lugar de hacerlo inmediatamente después de que se haya emitido PCNext.

Aquí está el código, así como la simulación:

 LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;
    USE ieee.numeric_std.ALL;

    ENTITY dlatch IS 
    PORT (
         Reset, Clock : IN std_logic;
         PC_out : OUT std_logic_vector(31 downto 0)
         );
    end dlatch;

    ARCHITECTURE d_arch OF dlatch IS

    SIGNAL PC      : std_logic_vector(31 downto 0);  
    SIGNAL PCNext  : std_logic_vector(31 downto 0);  

    BEGIN 
    PROCESS(Clock, Reset)  
    BEGIN 
         IF Reset = '1' THEN
              PC <= x"00000000";
         ELSIF Clock'event and Clock = '1' THEN
                PC <= PCNext;
         END IF;

        PCNext <= std_logic_vector(unsigned(PC) + 4); 

    END PROCESS;

    PC_out <= PC;

    END d_arch;

ingrese la descripción de la imagen aquí

¿Ves cómo PCNext solo se calcula en el flanco descendente del reloj? ¿Por qué no se calcula inmediatamente después PC <= PCNext?

No estoy seguro de por qué necesita PCnext aquí. Puede simplemente incrementar la PC en cada borde del reloj. En cualquier caso, necesitaría tener la declaración de incremento dentro de la condición de borde del reloj.

Respuestas (2)

En primer lugar, ambas dudas (1) y (2) que en realidad hacen la misma pregunta

(1) La adición del contador de programa solo se realiza en el siguiente evento de reloj [es decir, aquí es el flanco descendente], en lugar de hacerlo inmediatamente después de que se haya generado PCNext.

(2) ¿Ves cómo PCNext solo se calcula en el flanco descendente del reloj? ¿Por qué no se calcula inmediatamente después de PC <= PCNext?]

Respuesta : Es porque la señal PC no está presente en la lista de sensibilidad. Como se muestra en la simulación a continuación, cuando lo agrego en la lista de sensibilidad, la adición se realiza de inmediato porque PCNext <= std_logic_vector(unsigned(PC) + 4);se ejecuta simultáneamente cuando el cambio signal PCen la lista de sensibilidad invoca el proceso nuevamente.

ingrese la descripción de la imagen aquí

Anteriormente, en su caso, la asignación inmediata no sucedía hasta el próximo evento de reloj (que es el borde descendente del reloj presente en la lista de sensibilidad).

Espero que ahora entiendas la lista de sensibilidad y tengas más cuidado la próxima vez.

Una cosa más que puede hacer es declarar signal PCcomo variable PCy usar la asignación de bloqueo :=, esto también actualizará el resultado de la adición de inmediato y también puede obtener más información sobre la diferencia entre la asignación de bloqueo y la asignación sin bloqueo.

editar: como ya dijo Dave Tweed, mover la declaración PCNext <= std_logic_vector(unsigned(PC) + 4);fuera del bloque de proceso por completo también funcionará.

¡Gracias @Sourabh! Pero por curiosidad, pensé que los procesos eran secuenciales (como la programación en C), entonces, ¿por qué no se PCNext <= std_logic_vector(unsigned(PC) + 4);ejecutaba justo después de la if declaración?
Esto no es software, en VHDL el orden de las declaraciones en un proceso controla la prioridad, no la secuencia al menos en lo que a señales se refiere, solo hay un único punto de asignación al final del proceso y asigna cualquiera que sea el último valor de cada señal tenía, luego comienza un nuevo ciclo delta si alguna asignación cambió algo en la lista de sensibilidad.
@LiamF-A: sí, dentro del bloque de proceso sigue secuencial (como el programa C) para declaraciones if else, bucles for, declaraciones Case, etc. porque son prioridades condicionales pero 2 o más asignaciones de señales escritas dentro o fuera de estos subbloques condicionales pero dentro del proceso se ejecuta concurrentemente/simultáneamente [como el programa VHDL :)] por ejemplo, PCNext_1 <= std_logic_vector(unsigned(PC) + 4); PCNext_2 <= std_logic_vector(sin firmar(PC) + 3); tanto PCNext_1 como PCNext_2 obtienen el valor resultante simultáneamente.

La razón por la que PCNextno cambia hasta el siguiente borde del reloj es que tiene esa declaración dentro del process. El proceso solo se evalúa cuando cambia una de las señales en su lista de sensibilidad.

Tenga en cuenta que esta es una de las diferencias clave entre la simulación y el mundo real. El simulador presta atención a las listas de sensibilidad, pero si realmente sintetiza esta lógica, PCNextde hecho cambiaría de inmediato.

Para obtener el comportamiento que espera en el simulador , debe mover esa declaración fuera del proceso por completo.

¡Gracias @Dave! Usaría esta respuesta, solo los requisitos de este proyecto dicen que tengo que codificar la PC en unprocess
En ese caso, ¿por qué tenerlo PCNext? Simplemente actualice PCde la misma manera que lo hace, cyclees decir,PC <= std_logic_vector(unsigned(PC) + 4);
Estoy completamente de acuerdo, pero nuestro maestro nos dio una lista de señales que teníamos que usar. Supongo que quiere que recreemos este diagrama usando VHDL.
Para cuando tenga ese diagrama completamente implementado, tendrá lógica adicional para manejar ramas incondicionales/condicionales absolutas/relativas (¿y llamada/retorno de subrutina? Pero no veo rutas para transferir la PC a/desde la memoria). En cualquier caso, tiene aún menos sentido tener un bus separado dedicado PCNextsolo.