Tiene un módulo que debe procesar los datos varias veces seguidas para completar la conversión. En el ejemplo 'canalizado', simplemente alimenta cada uno por turno. Esto tendrá algo de latencia ya que los datos tardan un tiempo en ir desde la entrada a la salida. Sin embargo, si los bloques son realmente segmentados, esto es solo una latencia: puede ingresar una nueva palabra de datos en cada ciclo, y habrá múltiples muestras en la etapa de canalización en cualquier punto que permita el mismo rendimiento al final.
Su caso 'paralelo' no es realmente un caso paralelo. Básicamente es el mismo caso canalizado, pero en lugar de pegarlos uno tras otro, se obtiene una lógica adicional para distribuir los datos entrantes a cada bloque, y luego, presumiblemente, cada bloque tiene más lógica para alimentar su salida a través de sí mismo lo suficiente como para Completa la conversión. Al final tienes que combinarlos todos. Básicamente es un método feo para hacer un cálculo segmentado.
¿No estoy seguro de dónde obtiene la idea de que su canalización debe tener 2,4,8,16 unidades? Si necesita procesar los datos a través del módulo 7 veces, simplemente pegaría 7 en una fila en la tubería - cada uno opera en la salida del último, así que no importa si no es una potencia de dos longitudes .
Una versión verdaderamente paralela, sería aquella en la que el cálculo se puede dividir en operaciones parciales. Digamos, por ejemplo, que quería multiplicar dos números de 16 bits, pero solo tenía un bloque de multiples 8x8 que toma un ciclo de reloj para completarse. Podría pegar 4 en serie y tener cierta acumulación (esto sería una operación canalizada), o podría agregar varias instancias del multiplicador y ponerlas en paralelo. En paralelo, el resultado tendría 1 latencia de ciclo de reloj, en canalización (serie) tendría 4 latencia de ciclo. Esto tiene el costo de usar 4 veces más lógica.
Otro ejemplo de comportamiento paralelo verdadero es si necesita procesar varias palabras a la vez, y más rápido de lo que un bloque podría manejar. Digamos que tenía un bloque que tomó una palabra de datos y la cifró. El bloque solo puede manejar una palabra en su entrada en cada ciclo de reloj. Ahora, ¿qué pasa si su flujo de datos entrantes consiste en cuatro palabras que llegan todas en el mismo ciclo de reloj, pero su bloque de cifrado solo puede manejar una a la vez? El rendimiento del módulo de cifrado es 1/4 de lo que se requiere. Ahora, si coloca cuatro bloques en paralelo, ahora puede procesar cada una de las cuatro palabras al mismo tiempo, lo que permite el rendimiento requerido, de nuevo a costa de requerir cuatro veces más lógica.
Hay un caso en el que el segundo enfoque está realmente justificado. Digamos que necesita procesar cada palabra a través de la etapa de cálculo 8 veces, pero debido al tamaño del cálculo, solo tiene espacio en el FPGA, por ejemplo, 3 pases, entonces necesitará una forma de reutilizar recurso. Está intentando romper el cálculo para usar menos bloques.
En esta situación, sí, tener lógica para realimentar el mismo bloque varias veces es bastante ventajoso. Esto le permite reutilizar el mismo módulo y muchos menos recursos lógicos para procesar el cálculo. Sin embargo, esto viene a expensas del rendimiento. Si necesita pasar la misma palabra de datos a través del mismo bloque 8 veces, entonces su rendimiento se reduce a un octavo, porque mientras lo hace, no pueden ingresar palabras nuevas al bloque.
Tener espacio para bloques adicionales (por ejemplo, 3) le permitiría realizar el cálculo en paralelo para tres palabras de datos a la vez. Crea una instancia de tres copias de su circuito de bloque único y agrega alguna lógica adicional para determinar cuándo es hora de que una nueva palabra ingrese a cada uno de los bloques. Esto, a su vez, recupera algo de rendimiento, ahora es 3/8 de lo que era.
Puedo actualizar la respuesta con algunos diagramas si es necesario, pero espero que la explicación sea bastante clara.