Dividir por entero en VHDL

Necesito dividir un entero por un entero en un ciclo de reloj. ¿Cómo debería hacer esto? Tengo una función para ella que encontré en Internet, pero siempre devuelve una.

function  divide  (a : unsigned; b : unsigned) return integer is
    variable a1 : unsigned(15 downto 0):=a;
    variable b1 : unsigned(15 downto 0):=a;
    variable p1 : unsigned(16 downto 0):= (others => '0');
    variable i : integer:=0;
    begin
        for i in 0 to b'length-1 loop
            p1(b'length-1 downto 1) := p1(b'length-2 downto 0);
            p1(0) := a1(a'length-1);
            a1(a'length-1 downto 1) := a1(a'length-2 downto 0);
            p1 := p1-b1;
            if(p1(b'length-1) ='1') then
                a1(0) :='0';
                p1 := p1+b1;
            else
                a1(0) :='1';
            end if;
        end loop;
        return to_integer(a1);
    end divide;
La división siempre es un poco más difícil que la multiplicación. Piensa en multiplicar por el recíproco y obtener el recíproco del divisor de una tabla de consulta.
Tal vez "variable b1: sin firmar (15 hasta 0): = b;" en lugar de ...":=a"
¿Son sus entradas (dividendo y divisor) ambas variables? Es posible hacer un divisor de 1 ciclo, pero funcionará a baja frecuencia y ocupará mucha área (bueno, por supuesto, depende del ancho de los operandos...).
¿Latencia de un ciclo o rendimiento de un ciclo?
Latencia de un ciclo. Arreglé mi código con la sugerencia que hizo @TEMLIB pero ahora estoy usando más recursos de los que mi FPGA puede manejar. ¿Cómo podría usar menos recursos en mi código?
Un divisor de 16 bits de latencia de ciclo es una muy mala idea. Requiere 16 sumadores consecutivos, lo que significa mucha área y una ruta crítica muy larga. Si puede vivir con una aproximación, multiplicar por inversa sería mejor, pero para 16 bits requiere mucha ROM ... Algún algoritmo de división debería producir un circuito más pequeño (como SRT-4) y una división más rápida, pero requiere el MSB de divisor ser siempre '1'.
cuando dices aproximacion a que te refieres? No recibiré un flotador, por lo que está bien redondear. Multiplicar por el inverso sería invertir el entero y multiplicar, ¿no? @JonathanDrolet
Por aproximación, quiero decir que no obtendrá el valor exacto, pero sí bastante cercano. Esto se debe a que muchas inversas no se pueden representar exactamente en binario. La precisión general depende de su precisión en la representación inversa (por lo tanto, el tamaño de la ROM y el multiplicador). Por ejemplo, si quiere hacer 12345/45 (debería dar 274) y dar 16 bits para representar 1/45 (1456), el resultado de multiplicar por inversa es 278. Obtendría un error menor usando una ROM de más de 16 bits.
¿Qué tan grande necesitaría un multiplicador para obtener 274 en lugar de 278 para su ejemplo? Estoy diseñando un procesador en VHDL y la precisión es importante en esa medida. @JonathanDrolet
Tendrías que hacer ese análisis por ti mismo, pero sin error para un divisor de 16 por 16 bits: muy grande. Todos los procesadores que existen realizan divisiones en múltiples ciclos, del orden de 1 ciclo de reloj por bit. Los procesadores más pequeños no tienen un divisor de hardware, dependen de la implementación del software (mucho más lento). Generalmente, el compilador y el buen programador evitan a toda costa la división ya que es inherentemente lenta. Si desea agregar un solo divisor de latencia a su procesador, todas las demás operaciones serían más lentas como resultado de la ruta crítica más grande.
No tan aplicable a esta pregunta, pero en beneficio de Googlers: la división por una potencia de dos es muy barata en hardware, solo implica cambiar bits a la derecha.
Entonces, ¿cuáles son los pasos lógicos para no tener errores, una división de 16 bits de latencia de ciclo? Estaré dividiendo por números algo aleatorios. todo de 0 a 65535.
@JonathanDrolet Lo hice funcionar, me refiero al código anterior. ¡La división ahora me da un resultado diferente cada vez! ¿por qué?

Respuestas (2)

Esta respuesta no es lo que está buscando, pero la solución básica a este problema es esta: no use la división .

Muchas arquitecturas de procesador e incluso chips DSP no tienen ninguna instrucción de división y, cuando la tienen, suele ser una operación de varios ciclos, porque la división es fundamentalmente iterativa. La división es costosa en términos de área y lenta, por lo que generalmente se evita si es posible.

Sugiero encarecidamente que usted o cualquier persona que lea esta pregunta se esfuerce por evitar implementar una función de división de hardware de cualquier tipo, y mucho menos una de ciclo único. Como han dicho algunos comentarios, el enfoque estándar sería implementar una multiplicación por el recíproco del divisor. Incluso aquí, si espera un buen rendimiento en su FPGA, esto se implementaría utilizando una arquitectura canalizada y, por lo tanto, no tendría una latencia de ciclo único.

Una solución aún mejor sería revisar su diseño de manera que no haya necesidad de ninguna división o equivalente. Sin embargo, sin saber lo que se supone que debe hacer su diseño, es imposible sugerir alternativas.

Como nota a pie de página, y como se señaló en un comentario, la división por una potencia de dos es relativamente simple, porque se reduce a una operación de cambio.

Todavía NECESITARÉ hacer la división. ¿Cómo haría la división de varios ciclos? Estoy haciendo un procesador en una fpga y la división será más que necesaria. No se requiere código, pero se prefiere. Lamento molestarle de nuevo.
Le sugiero que cree un procesador que funcione e implemente una rutina de división en el software. Esto es lo que se ha hecho en la mayoría de los diseños de procesadores durante décadas. La mayoría de los programadores son conscientes de que 'dividir' es costoso y no colocarían esta operación en un bucle interno u otra sección de código crítica. Siempre puede regresar y agregar algún soporte de división de hardware más tarde, si esto resulta ser un cuello de botella real en su aplicación.

El algoritmo que diste originalmente es un algoritmo de 'restauración de la división'; requiere un ciclo de reloj para cada bit del cociente. La división sin restauración se usa normalmente en hardware; esto también toma un ciclo por bit del cociente. Hay alrededor de mil millones de visitas de Google en la división de no restauración. Es simple, pero un poco complicado: pruébalo y pregunta si/cuándo no funciona.

Ni siquiera piense en invertir/multiplicar a menos que el dividendo sea una constante, en cuyo caso es fácil y rápido, y ni siquiera requerirá un multiplicador (puede usar sumadores en su lugar).