SystemVerilog: condición de carrera en la memoria

0

Hola, seré breve porque mi inglés no es bueno gracias por su paciencia

Estoy trabajando en un sistema que controla esta memoria:

module Buffer_m #(
parameter Word=8,
parameter bits_Buffer_address)
(
    input  logic Clk,
    input  logic [bits_Buffer_address-1:0] Address_R,
    input  logic [bits_Buffer_address-1:0] Address_W,
    input  logic R,
    input  logic W,
    input  logic [Word-1:0] Data_buffer_in,
    output logic [Word-1:0] Data_buffer_out
);

localparam  Buffer_deep = 1 << bits_Buffer_address;
logic [Word-1:0] Buffer [Buffer_deep-1:0];

always_ff @(posedge Clk)
begin
    if (R) begin
        Data_buffer_out<=Buffer[Address_R];
    end
    else Data_buffer_out<= '0;
    if (W) begin
        Buffer[Address_W]<=Data_buffer_in;
    end
end

endmodule // Buffer

y dé estos resultados Imagen1:correctofuncionamiento

Creoqueesteesuncomportamientonormal,perocuandoloconduzcoconmimódulounpardeFSM(nomuestratodo,son277líneas)Nocreoqueestoseaunproblemaconlalógicasinoconlasintaxisuotracosa.

assignAddress_R=Reg_address_R_Buffer;assignAddress_W=Reg_address_W_Buffer;...assignR=R_Data||R_Bus;assignW=W_Data||W_Bus;......always_ff@(posedgeClk)beginif(Reset||Address_W_0)beginReg_address_W_Buffer<='b0;endelsebeginReg_address_W_Buffer<=Reg_address_W_Buffer+Address_W_1;endend//FSMalways_ff@(posedgeClk)beginif(Reset)State_data_in<=2'd0;elseState_data_in<=Next_data_in;end...always_combbegin...W_Data=1'b0;case(State_data_in)2'd0:begin...end2'd1:begin...W_Data=1'b1;...end

ydelamismamaneraparaR,

Esperoqueestoseasuficientecódigo......

yesomedalasmismasformasdeondaparalasentradasperolassalidassonincorrectas

Imagen2:funcionamientoincorrecto

Comoves,noguardaelprimerbyte,creoqueesunacondicióndecarreraperoNoestoytanseguro.

------------------------------------------------------EDITAR---------------------------------------------------------

LoejecutéenSynopsysVCSymedioresultadosdiferentesalosdelaimagen2

Imagen3:trabajoincorrectoenVCS

Noséporqué,peroModelimretrasóWunciclodereloj,asíquecontinuaréconVCS

Como@Oldfartseñalóhayunacondicióndecarreracuando(R&&W&&Address_R==Address_W)peroelproblemapersisteinclusoconR=0

Imagen 4: Aún no funciona con R = 0

Creo que podría ser que el búfer lea W antes de que mi módulo lo actualice en la posición pero no estoy seguro.

Gracias por tu tiempo.

    
pregunta Autoreiv

2 respuestas

0

No muestra todo su código pero básicamente:

if (R) begin
    Data_buffer_out<=Buffer[Address_R];
end
else Data_buffer_out<= '0;
if (W) begin
    Buffer[Address_W]<=Data_buffer_in;
end

Ese código en sí mismo es una condición de carrera si R y W están ambos activos y Address_R es igual a Address_W .

No es un código incorrecto, porque así es como funcionan todas las memorias de doble puerto en ASICs ++ . Hay dos soluciones al problema:

  • Asegúrate de que nunca suceda.

  • Captura / reconoce la condición y lidia con ella.

El primero es el caso si, por ejemplo, tener una FIFO. Normalmente no lee desde FIFO hasta después de que se haya escrito. En todos los años que he trabajado con memorias de doble puerto, este ha sido el caso en el 99% del código.

Este último requiere que compares las direcciones y "hagas algo". p.ej. Si ve una lectura y un error de escritura, puede ignorar el resultado de la lectura y devolver los datos de escritura. Obtienes un código a lo largo de las líneas de:

if (R && W && Address_R==Address_W)
begin
   <do something special>
else
   <normal action> 

En realidad, es un poco más complejo y la solución real depende de si desea tenerlo, leer después de escribir (Leer devuelve los datos que se están escribiendo) o escribir después de leer (se devuelven los datos antiguos, se escriben nuevos datos)

++ Muchos proveedores de FPGA le permiten especificar el comportamiento de lectura después de escribir o escritura después de leer usando un parámetro cuando instale su bloque de memoria de doble puerto.

    
respondido por el Oldfart
0

Teniendo en cuenta tu último comentario, creo que tu problema de carrera se debe a las declaraciones de bloqueo en otro FSM cronometrado.

Considere el siguiente código:

always @(posedge clk) addr = addr + 1;   // proc1 (blocking statement)
always @(posedge clk) data <= mem[addr]; // proc2 (non-blocking statement)

El simulador evaluará los dos procesos sin un orden definido. En este caso hay dos opciones:

Supongamos que addr comienza en 0 en ambos casos.

  1. El primer proceso se evalúa; el RHS se evalúa a 1 y luego el LHS (addr) se actualiza inmediatamente a 1. El siguiente proceso se evalúa a continuación y el RHS se evalúa como mem [1].

  2. El primer proceso proc2 se evalúa, y el RHS se evalúa como mem [0]. A continuación se evalúa proc1; RHS se evalúa como 1 y luego LHS se actualiza inmediatamente a 1.

En ambos casos, después de evaluar los dos procesos (y de todos los demás procesos activados por el registro de posición), los LHS (datos) se actualizan con las expresiones RHS tal como se evaluaron anteriormente. En la primera opción, los datos se obtienen mem [1], y en la segunda información se obtienen mem [0].

Lo importante aquí es que los datos se leen desde una dirección de memoria diferente dependiendo de una orden indefinida de ejecución.

Mi lema personal actual es no usar instrucciones de bloqueo en procesos cronometrados, excepto a las variables que se declaran dentro del proceso (alcance local al proceso). Sin embargo, soy nuevo en SV, así que no estoy completamente seguro de qué tan bien funciona este último con la síntesis, pero no parece ser un problema para la simulación.

    
respondido por el HKOB

Lea otras preguntas en las etiquetas