División entera en Verilog
Publicado: 01 Oct 2019, 22:50
Estaba yo esta tarde preparando la clase de mañana (estamos con lo básico del binario) y me he dado cuenta de que cuando les enseño a operar en binario, lo hago usando sumas, multiplicaciones, y cuando damos el complemento a 2, les enseño que restar es sumar. Total, que siempre les digo que no les hago nada de dividir porque es más complejo.
O eso pensaba yo.
Me da esta tarde por hacer unas pruebas y he visto que es tan trivial como la multiplicación binaria. Para comprobarlo del todo, he escrito un módulo en Verilog que divide dos números de 32 bits sin signo (división entera), devolviendo el cociente entero y el resto.
Parto de un algoritmo completamente "naive" y no pretende ser rápido ni nada de eso. Tarda N+1 ciclos de reloj en proporcionar un resultado final, donde N es el número de bits que tengan los operandos. Tampoco detecto división por 0 (si divides entre 0, lo único que pasa es que obtienes un resultado erróneo)
Lo he escrito como siempre, usando EDA Playground como herramienta para hacer mis "bocetos" en Verilog. Está el módulo y un pequeño testbench para probar valores que pongas en el código.
https://www.edaplayground.com/x/5YDu
O eso pensaba yo.
Me da esta tarde por hacer unas pruebas y he visto que es tan trivial como la multiplicación binaria. Para comprobarlo del todo, he escrito un módulo en Verilog que divide dos números de 32 bits sin signo (división entera), devolviendo el cociente entero y el resto.
Parto de un algoritmo completamente "naive" y no pretende ser rápido ni nada de eso. Tarda N+1 ciclos de reloj en proporcionar un resultado final, donde N es el número de bits que tengan los operandos. Tampoco detecto división por 0 (si divides entre 0, lo único que pasa es que obtienes un resultado erróneo)
Lo he escrito como siempre, usando EDA Playground como herramienta para hacer mis "bocetos" en Verilog. Está el módulo y un pequeño testbench para probar valores que pongas en el código.
https://www.edaplayground.com/x/5YDu
Código: Seleccionar todo
module division (
input wire clk,
input wire [31:0] dividendo,
input wire [31:0] divisor,
output reg [31:0] cociente,
output reg [31:0] resto,
input wire start,
output wire busy
);
reg [33:0] contador = 34'h200000000; // one hot.
assign busy = ~contador[33]; // cuando llega al ultimo estado, busy = 0 y terminamos
wire no_desplaza_resto = contador[32]; // penultimo estado. Se actualiza el cociente, pero no el resto
reg [31:0] rdivisor;
reg [31:0] proximo_resto;
reg [63:0] proximo_restocociente;
always @(posedge clk) begin
if (busy == 1'b0 && start == 1'b1) begin
cociente <= dividendo; // el dividendo se va desplazando a la izquierda, y el cociente entra por la derecha
rdivisor <= divisor; // guardamos el divisor
resto <= 32'h00000000; // el resto es el dividendo parcial que en cada ciclo es comparado con el divisor
contador <= 34'h000000001; // contador one-hot. Se desplaza a la izquierda
end
else if (busy == 1'b1) begin
contador <= {contador[32:0], contador[33]}; // contamos un estado
{resto, cociente} <= proximo_restocociente; // asignamos el cociente y resto
end
end
always @* begin
proximo_resto = resto - divisor; // proximo dividendo parcial. Solo se usa si el actual es >= divisor
if (resto < rdivisor) begin // si el dividendo parcial actual es menor que el divisor
if (no_desplaza_resto == 1'b0) // y hay que desplazar el resto
proximo_restocociente = {resto[30:0], cociente, 1'b0}; // simplemente desplazamos cociente y resto a la izquierda
else // y por la derecha entra un 0
proximo_restocociente = {resto, cociente[30:0], 1'b0}; // si no hay que desplazar el resto, entonces splo se
end // desplaza el cociente
else begin // si el dividendo parcial actual es mayor que el divisor
if (no_desplaza_resto == 1'b0) // y hay que desplazar el resto
proximo_restocociente = {proximo_resto[30:0], cociente, 1'b1}; // entonces se hace todo el desplazamiento, pero
else // usando proximo_resto en lugar de resto
proximo_restocociente = {proximo_resto, cociente[30:0], 1'b1}; // si no se desplaza el resto, pues solo se hace
end // en el cociente
end
endmodule