Simulación de Verilog: ¿Cómo puedo iniciar mi circuito después de que se apague la señal de reinicio?

1

Intenté implementar el FIFO simple y su banco de pruebas.

Código FIFO Testbench:

'timescale 1ns / 1ps

module fifo_tb();
  localparam B=4, W=2; //4bit sized 4 entry fifo
  localparam T=20;
  reg clk, reset;
  reg rd, wr;
  reg [B-1:0] w_data;
  wire [B-1:0] r_data;
  wire empty, full;

  fifo fifo
  (.clk(clk), .reset(reset), .rd(rd), .wr(wr),
   .w_data(w_data), .empty(empty), .full(full),
   .r_data(r_data));

  always begin
    clk = 1'b1;
    #(T/2);
    clk = 1'b0;
    #(T/2);
  end

  initial begin
    reset = 1'b1;
    #(T/2);
    reset = 1'b0;
  end

  initial begin
    wr = 1;
    rd = 0;
    w_data = {B{'b1000}};
    @(negedge reset);
    @(negedge clk);

    w_data = {B{'b0100}};
    @(negedge clk);

    w_data = {B{'b0010}};
    @(negedge clk);

    w_data = {B{'b0001}};
    @(negedge clk);

    $stop;
  end
endmodule

Código del módulo FIFO:

module fifo

#(

  parameter B=8, // number of bits in a word

            W=4 // number of address bits

)

(

  input wire clk, reset,

  input wire rd, wr,

  input wire [B-1:0] w_data,

  output wire empty, full,

  output wire [B-1:0] r_data

);

  reg [B-1:0] array_reg [2**W-1:0];

  reg [W-1:0] w_ptr_reg, w_ptr_next, w_ptr_succ; //tail

  reg [W-1:0] r_ptr_reg, r_ptr_next, r_ptr_succ; //head

  reg full_reg, empty_reg, full_next, empty_next;

  wire wr_en;



  //register file write operation

  always @(posedge clk)

    if (wr_en)

      array_reg[w_ptr_reg] <= w_data;



  //register file read operation

  assign r_data = array_reg[r_ptr_reg];

  //write enabled only when FIFO is not full

  assign wr_en = wr & ~full_reg;



  //fifo control logic

  //register for read and write pointers

  always @(posedge clk, posedge reset)

    if (reset)

      begin

        w_ptr_reg <= 0;

        r_ptr_reg <= 0;

        full_reg  <= 1'b0;

        empty_reg <= 1'b1;

      end

    else

      begin

        w_ptr_reg <= w_ptr_next;

        r_ptr_reg <= r_ptr_next;

        full_reg  <= full_next;

        empty_reg <= empty_next;

      end



  //next state logic for read and write pointers.

  always @*

    begin

      //successive pointer values

      w_ptr_succ = w_ptr_reg + 1;

      r_ptr_succ = r_ptr_reg + 1;

      //default: keep old values.

      w_ptr_next = w_ptr_reg;

      r_ptr_next = r_ptr_reg;

      full_next  = full_reg;

      empty_next = empty_reg;

      case ({wr, rd})

        // 2'b00 no op

        2'b01: //read

          if (~empty_reg) // not empty

            begin

              r_ptr_next = r_ptr_succ;

              full_next = 1'b0;

              if (r_ptr_succ == w_ptr_reg)

                empty_next = 1'b1;

            end

        2'b10: //write

          if (~full_reg) // not full

            begin

              w_ptr_next = w_ptr_succ;

              empty_next = 1'b0;

              if (w_ptr_succ == r_ptr_reg)

                full_next = 1'b1;

            end

        2'b11: //write and read

          begin

            w_ptr_next = w_ptr_succ;

            r_ptr_next = r_ptr_succ;

          end

      endcase

    end



  //output

    assign full  = full_reg;

    assign empty = empty_reg;



endmodule

Por lo que yo sé poniendo @ (negedge clk); hace que el código se actualice

para ser ejecutado en el borde negativo del reloj, y

poniendo @ (negedege clk); @ (negedge claro); back to back hace que el código se ejecute en el borde negativo del reloj que se genera después de que el borrado se convierte en cero.

Por lo tanto, he esperado que el primer bloque de código en el bloque inicial

    wr = 1;
    rd = 0;
    w_data = {B{'b1000}};
    @(negedge reset);
    @(negedge clk);

se ejecutará después del reinicio < = 0 y clk < = 0 (es decir, 30 ns en la siguiente simulación).

Sin embargo, el resultado de la simulación muestra que los valores wr, rd, w_data se establecen en el primer flanco ascendente del reloj, no en las 30 ns. ¿Qué bloque de código generó este resultado de simulación no deseado?

He intentado depurarlo, pero aún me cuesta encontrarlo ...

Aprecio cualquier ayuda.

    
pregunta JaeHyuk Lee

1 respuesta

0

Comenzaría manteniendo el restablecimiento con el restablecimiento de su código de prueba, por lo tanto, no en una declaración inicial aparte. Sus problemas comienzan con:

@(negedge reset);
@(negedge clk);

Esa es una condición de carrera, ya que el reinicio y el reloj tienen el mismo retardo de tiempo: "# (T / 2);". Nunca está de más tener su reinicio activo un poco más (por ejemplo, podría tener el módulo de otra persona que tenga un reinicio síncrono). Mis bancos de pruebas se parecen a todos:

localparam CLK_PERIOD=100;
... 
initial
begin
   reset_n   = 1'b0;
   ... 

   #(CLK_PERIOD*10) ;
   reset_n = 1'b1;
   #(CLK_PERIOD*4) ;
   // This is where the testing starts
   @(posedge clk) 

Soy propietario de un sitio web que proporciona el código completo y gratuito de Verilog con los bancos de prueba y NO tiene publicidad, pero no conozco las reglas exactas de stackexchange, por lo que no puedo indicarle.

    
respondido por el Oldfart

Lea otras preguntas en las etiquetas