División entera en Verilog

Diseño HDL con este lenguaje. Módulos y testbenchs. Estilos y trucos de codificación, etc. NOTA: dado que hay entornos como ISE que soportan Verilog pero no SystemVerilog, señalad dentro de un post que de lo que se va a tratar es SystemVerilog si es el caso.
Responder
Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

División entera en Verilog

Mensaje por mcleod_ideafix » 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

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

Bitwise
Veroboard
Mensajes: 1
Registrado: 18 Feb 2021, 09:19

Re: División entera en Verilog

Mensaje por Bitwise » 27 Jun 2021, 16:57

Hola "macleod_ideafix",

Quería darles las gracias por el algoritmo de división entera. Para sintetizar circuitos utilizo un IDE gráfico llamado "Icestudio", en el que se puede diseñar pequeños módulos (éstos, a su vez también pueden contener otros módulos). Adapté su algoritmo (para Icestudio) para crear la de 32 bits (original) y también otras dos de 16 y 8 bits.

Nada de esto hubiera sido posible si no me hubiera encontrado con este enlace, y de nuevo darle las gracias por compartir su conocimiento.

Un saludo.

Post data:
Aquí publiqué la adaptación para Icestudio de su algoritmo: https://groups.google.com/g/fpga-wars-e ... 4peAx9AQAJ

Responder

Volver a “Verilog / SystemVerilog”