Implementando CRC paralela en verilog

1

Estoy intentando implementar un CRC paralelo en Verilog pero tengo problemas para que funcione. Este es un fragmento del código con el que estoy teniendo problemas.

  reg val;
  reg [15:0] hashValue;
  reg [3:0] data_in;
  always @(*) begin 
    if(reset) begin
        hashValue=16'h58a9; //initial hashvalue
        poly=16'h1021; //the polynomial 
    end
    for(i=0; i < 4; i=i+1) begin
        val=hashValue[15];
        hashValue={hashValue[14:0],data_in[0]};
        if(val) hashValue=hashValue ^ poly;
        data_in=data_in >> 1;
     end
   end

El bloque crc admitirá una entrada de 4 bits. El código está dentro de un bloque combinacional siempre @ (*). El problema es cuando los dos nibbles consecutivos del mismo tipo entran a través de data_in que no hay ningún cambio en el valor de hash. ¿Qué estoy haciendo mal?

    
pregunta user7994

2 respuestas

4

Este es un buen ejemplo de desajuste en los resultados entre simulación y síntesis.

Si sintetizará este código y ejecutará una prueba en FPGA, funcionará (al menos no verá un valor hash constante). Sin embargo, en la simulación se comporta de manera diferente:

  • always @(*) construct significa "evaluar el siguiente bloque de código en cualquier momento en cualquiera de las señales utilizadas en el lado derecho del cambio de asignación". En su código, estas señales son: data_in , poly y hashValue .
  • Si ninguna de las señales anteriores cambia (¿cuál es el caso que está describiendo, verdad?) - el simulador no evaluará el bloque y no se harán las asignaciones.

Una vez más, la herramienta de síntesis producirá la lógica correcta para este código, por lo tanto, este tipo de errores son muy peligrosos .

Hay una forma correcta de manejar esto es definir una señal de reloj y usar una construcción secuencial always @(posedge clk) .

Además, parece que tienes al menos dos bucles combinatorios en tu código. Incluso si están destinados, esta es una muy mala práctica. Desea evitar el uso de cualquier bucle comb de sintetizable.

Sin embargo, al inspeccionar su código, parece que la referencia circular aquí es solo por conveniencia, tal vez no se sintetice en un bucle de peine. En este caso tienes dos opciones:

  1. Encuentre un formulario equivalente que no use una referencia circular
  2. Use Verilog function construct.

El primer enfoque es el correcto. Verilog no es un lenguaje de programación, y las declaraciones que está utilizando para describir la lógica deben ser lo más similares a la lógica inferida. Sin embargo, este enfoque puede ser complicado, ya que muchos algoritmos están escritos en formularios de software. Por lo tanto, puede utilizar el segundo enfoque, en cuyo caso el código se verá así (no probado):

always @(posedge clk)
begin
  hashValue[15:0] <= calcNewHashValue(hashValue[15:0], poly[15:0], data_in[3:0]);
end

Donde calcNewHashValue es la función que encapsula el bucle for de tu código.

Una vez más: si la herramienta de síntesis le advierte sobre los bucles de peine, no debe usar este diseño. En este caso, piense en otra implementación algorítmica o distribuya el cálculo en varios ciclos de reloj.

También puede leer este documento para obtener una comprensión más profunda del comportamiento de los simuladores Verilog.

Excepto por eso, su estilo de codificación es muy propenso a errores. Como guía, sugiero que defina un bloque always separado para cada señal. En otras palabras, solo se asigna una señal en el bloque always . Haga excepciones solo cuando no pueda manejarlo de otra manera, y piense detenidamente antes de cada decisión.

    
respondido por el Vasiliy
0

Así es como logré que funcionara. Hice una función y la llamé en el bloque principal siempre @ (reloj de posición). Muchas gracias @Vasiliy. Eso ayudó mucho. :)

always @ (posedge clk or posedge reset)
if (reset) begin
    crc_v <= #1 16'h58A9;
end 
else if(startcrc_flg) 
begin
    //crc_in <= #1 data_in;
    crc_v <= #1 next_crc(crc_v[15:0],POLY[15:0],crc_in[3:0]);
end else begin
    crc_v <= #1 crc_v;
    i <= #1 5;
end


function [15:0] next_crc;
input [15:0] crc_v;
input [15:0] POLY;
input [3:0] crc_in;



integer i;

begin

if (startcrc_flg) begin
for(i=0; i <4; i=i+1) 
begin
    crc_reg=crc_v[15];
    crc_v={crc_v[14:0],crc_in[0]};
    if(crc_reg) crc_v=crc_v ^ POLY;
    crc_in = crc_in >> 1;
end
end
next_crc = crc_v;


end
endfunction
    
respondido por el user7994

Lea otras preguntas en las etiquetas