Estoy trabajando en el curso abierto de Nand to Tetris ofrecido por Nissan y Schoken. Acabo de terminar el capítulo 5, donde construimos una computadora de 16 bits con un lenguaje de descripción de hardware y un simulador de hardware proporcionado por un instructor.
Creación de una computadora moderna desde los primeros principios: curso de Nand a Tetris
La CPU que construimos para la computadora usa tres componentes temporizados: un contador de programa, un registro de direcciones y un registro de datos. Puede ver un diagrama de la CPU en la página 94 del PDF a continuación, y un diagrama de toda la computadora en la página 97:
Capítulo 5 - Arquitectura de computadoras
La salida del contador del programa se conecta a una ROM externa que envía instantáneamente las instrucciones a la dirección especificada por el contador del programa. Si la instrucción emitida es una instrucción de "establecer dirección", se propaga instantáneamente al registro de dirección de la CPU, donde se almacenará en el siguiente flanco descendente del reloj.
Mi pregunta sigue. Tanto el contador de programas como el registro de direcciones son componentes sincronizados. Se conectan en serie, con la salida del contador del programa que se alimenta (eventualmente) a la entrada del registro de direcciones, de este modo:
___________________ _____________ ____________________
| program counter | | ROM 32K | | address register |
| ^ |--->| |----->| ^ |
|___________________| |_____________| |____________________|
En una implementación física de este circuito, ¿cómo podría asegurarme de que la salida de la ROM 32K se almacenaría correctamente en el registro de direcciones? Ambos componentes se actualizan en un flanco de reloj descendente. Imagine que la señal del flanco descendente toma .2 ciclos de reloj para alcanzar el contador del programa, lo actualiza y luego se propaga a través de la ROM, pero toma .8 ciclos de reloj para alcanzar el registro de direcciones. En este caso, la salida de la ROM cambiaría antes de que el flanco descendente del reloj llegue al registro de direcciones.
El simulador de hardware de nuestra clase resuelve este problema al almacenar nuevos estados de componentes en los flancos descendentes del reloj y luego propagar el nuevo estado de componentes en los flancos ascendentes del reloj. Esto garantiza que el componente B pueda capturar la salida del componente A antes de que el componente A genere un nuevo estado. Me preguntaba cómo se resolvería este problema en una implementación física.