¿Está bien usar tanto el borde ascendente como el descendente en este diseño VHDL?

Soy bastante nuevo en el diseño de hardware con VHDL y creo que estoy cometiendo un error de novato. Estoy haciendo una CPU y mi archivo de registro se activa en el borde ascendente. Sin embargo, tuve un problema. Intentaré poner algún pseudocódigo para aclararlo.

on rising_edge {r0in <= 20; }
CLOCK CYCLE
on rising_edge {r1in <= r0out; }
CLOCK CYCLE

Mi problema es que r1in obtendría el valor anterior de r0 en lugar del apropiado 20. Luego procedí a cambiar mi código para usar el borde descendente en lugar del borde ascendente solo para el archivo de registro. A continuación se muestra una versión simplificada:

process(WriteEnable, DataIn, Clock)
begin
  if falling_edge(Clock) then --note the falling_edge instead of rising_edge
    if(WriteEnable = '1') then
      registers <= DataIn;
    end if;
  end if;
end process;
DataOut <= registers;

Así que ahora mis registros se activan con borde descendente en lugar de borde ascendente. Todos los casos de prueba que tengo pasan con esta configuración y sintetiza sin advertencias... pero ¿es esto correcto?

Hago esta pregunta porque durante mucho tiempo me han dicho que solo use ambos bordes en un diseño si realmente sabe lo que está haciendo. He estado programando en VHDL durante algunas semanas, así que quiero asegurarme de que este sea un caso apropiado para usar ambos bordes.

Respuestas (2)

Sí, puedes, pero no es recomendable. Necesitará que el hardware sintetice al doble de la velocidad del reloj ahora: un bus de 100 MHz debe configurarse a 200 MHz porque los datos solo tienen la mitad del tiempo para propagarse. Efectivamente lo has hecho DDR .

Parece que en realidad no entiendes cómo funciona un proceso. Todas las salidas dentro de un proceso están programadas para presentarse en la salida en el próximo ciclo de reloj . Entonces, todo lo que codifica dentro de ese proceso está sucediendo en realidad en paralelo y debe estabilizarse antes de que llegue el próximo reloj, que es cuando se publicarán los resultados.

Lo que no entiendo entonces es cómo se hace una CPU en la que algunas instrucciones toman solo un ciclo de reloj. Esto parece imposible sin hacerlo de esta manera.
Por ejemplo, ¿cómo lo hace AVR?
Ok, esta es la respuesta, lo estaba haciendo mal. Mi DataOut debería haber sido así: DataOut <= registers when WriteEnable='0' else DataIn;. De esta forma, los valores escritos en los registros aparecen en el siguiente borde del reloj, en lugar del siguiente al siguiente. Pensé en hacer esto antes, pero no pensé que funcionaría bien. Todas mis pruebas ahora pasan con esto (aunque algunas de mis pruebas en realidad estaban equivocadas)
@Earlz, núcleo AVR muy incompleto en Verilog: bitbucket.org/avakar/pv200_avrcore/src/e085fd7d2023/avrcorev/… Debe buscar las instrucciones un ciclo antes de ejecutarlas. Por eso rjmplleva dos ciclos.
¡Timbre! Parece que lo tienes. :)

El código incorrecto funcionará si la parte de destino tiene esta capacidad. Como puede invertir el reloj y usar el flanco ascendente, lo hará. Sin embargo, el momento puede no ser el que deseas.

No necesita WriteEnable, DataIn en la sensibilidad del proceso.

Sin embargo, recibe advertencias si no las incluye en la sensibilidad del proceso (al menos de XST ... Sin embargo, conozco sus advertencias sin sentido)
@Earlz: Sospecho que lo que vio fueron advertencias de un proceso combinatorio con una lista de sensibilidad incompleta.
Brian Carlton tiene razón, la lista de sensibilidad depende solo de las señales que se usan en el "primer nivel" de las declaraciones if dentro de un proceso. En el ejemplo publicado, el proceso solo se "ejecuta" cuando hay un cambio en la señal del reloj; de lo contrario, no se "ejecuta".