1

I design a instruction cache, my problem is that when I change the sram index at posedge clk it returns the value of the previous index. When I test sram module it behaves normally, but I instantiate it in data_array and tag_array module it does not work properly and keep previous index data its output. I can't figure out why it behaves like this.

Here is some partion of my testbench :

module top_tb;

  // Parameters

  // Ports
  logic clk = 0;
  logic rst = 0;
  logic flush = 0;
  logic write_en = 0;
  logic [3:0] i_data;
  logic [9:0] pc;
  logic [3:0] o_data;

  top 
  top_dut (
    .clk      (clk ),
    .rst      (rst ),
    .flush    (flush ),
    .write_en (write_en ),
    .i_data   (i_data ),
    .pc       (pc ),
    .o_data   (o_data)
  );

  initial begin
    begin
      rst      = 1;
      flush    = 0;
      write_en = 0;
      i_data   = 0;
      pc       = 0;
      #10;
      // Flush cycle keep 16 cycle
      rst      = 0;
      flush    = 0; // no change
      write_en = 0;
      i_data   = 0;
      pc       = 0;
      #45;
        
      // end of flush
      write_en = 1;
      i_data   = 1;
      pc       = 1;
      #10;

      write_en = 1;
      i_data   = 2;
      pc       = 2;
      #10;
      write_en = 0;

    end
  end

  always
    #5  clk = ! clk ;

endmodule

Additionally, SRAM module is instantiated in data array module and data array module is instantiated in icache_top module. Top module get Program Counter as an input and inside the module, index information is extracted and assigned a wire which is named index. If I assign this signal to data array index port this problem happens, but when I directly drive the program counter index part to data array module this problem does not happen I want to learn why this stiuation happens in systemverilog (vivado)?

The code have wrong wave form:

`timescale 1ns / 1ps

module top(
    input  logic       clk,
    input  logic       rst,
    input  logic       flush,
    input  logic       write_en,
    input  logic [3:0] i_data,
    input  logic [9:0] pc,
    output logic [3:0] o_data
    );

  // Ports
  logic [1:0] index;
  assign index = pc[1:0];

  test test_ex (
    .clk         (clk),
    .rst         (rst),
    .i_flush     (flush),
    .i_wr_en     (write_en),
    .i_data      (i_data),
    .i_index     (index),
    .o_data      (o_data)
  );

endmodule

The code have correct wave form:

`timescale 1ns / 1ps

module top(
    input  logic       clk,
    input  logic       rst,
    input  logic       flush,
    input  logic       write_en,
    input  logic [3:0] i_data,
    input  logic [9:0] pc,
    output logic [3:0] o_data
    );

  // Ports
  logic [1:0] index;
  assign index = pc[1:0];

  test test_ex (
    .clk         (clk),
    .rst         (rst),
    .i_flush     (flush),
    .i_wr_en     (write_en),
    .i_data      (i_data),
    .i_index     (pc[1:0]),
    .o_data      (o_data)
  );

endmodule

The test module as following;

module test(
    input  logic       clk,
    input  logic       rst,
    input  logic       i_flush,
    input  logic       i_wr_en,
    input  logic [3:0] i_data,
    input  logic [1:0] i_index,
    output logic [3:0] o_data
);
    logic        flush_q;
    logic [15:0] memory [3:0];
    logic [1:0]  flush_index;
    logic [1:0]  wr_index;
    logic [15:0] wr_data;
    
    assign wr_data = flush_q ? '0 : i_data;
    assign wr_index = flush_q ? flush_index : i_index;
    always_ff@(posedge clk)begin
        if(i_wr_en | flush_q)begin
            memory[wr_index] <= wr_data;
        end else begin
          o_data <= memory[wr_index];
        end
    end
    
    always_ff @(posedge clk) begin
    if(rst) begin
      flush_q       <= 1'b1;
      flush_index   <= '0;
    end 
    else begin
      if(flush_q) begin
        if(flush_index == 3) begin  
          flush_index <= '0;
          flush_q     <= 1'b0;
        end else begin
          flush_index <= flush_index + 1'b1;
        end
      end else begin
        flush_q <= i_flush;
      end
    end
  end
endmodule

Note: Post is updated for basic example for this situation. If you compare two top module in first one I extract index form pc to index wire and then drive the test module and this module apply the write operation previous index. But in second top module if I drive pc[1:0] (index part) directly to test module data is written to the present index. Which behaviour correct? Is this a race condition?

2
  • @Mikef, sorry I have no permission to share all code block. Just I share clearly my question, some times face this problem assigning module input to another instantiated module directly work normally but assigning internal signal which created combinationally from input to instantiated module gives a one clock cycle delayed change at output. Commented Mar 2, 2023 at 23:46
  • @Mikef I updated the codes according to your advice you can check waveform easily by simulating this codes. Commented Mar 3, 2023 at 22:16

2 Answers 2

1

This is a testbench synchronization issue. The testbench stimulus block is re-written below to use synchronous methodology rather #10 delays. This synchronizes the testbench with the DUT. Otherwise data is changing at the clock edge and sampling at the dut is a race.
Use

@(posedge clk)    

with non-blocking assignments to eliminate the issue.
Here is that code:

  initial begin
      rst      <= 1;
      flush    <= 0;
      write_en <= 0;
      i_data   <= 0;
      pc       <= 0;
      repeat(2) @(posedge clk);
      //
      rst      <= 0;
      flush    <= 0; // no change
      write_en <= 0;
      i_data   <= 0;
      pc       <= 0;
      repeat(4) @(posedge clk);
      //        
      write_en <= 1;
      i_data   <= 1;
      pc       <= 1;
      repeat(1) @(posedge clk);
      //
      write_en <= 1;
      i_data   <= 2;
      pc       <= 2;
      repeat(1) @(posedge clk);
      write_en <= 0;
  end
Sign up to request clarification or add additional context in comments.

2 Comments

You need to use nonblocking assignments to your stimulus or use negedge clk to keep race conditions out of your testbench
Yes, that fixed the problem. I guess since no signal can change faster than the clock, all changes take effect in the next clock. In this case, it's like the first testbenchim was wrong, because there the answers were changing within the same cycle at the first rising edge. This writing style guarantees that, I guess @negedge will be a guaranteed way.
1

It is possible that there is a race on index. Maybe you use a blocking assignment to assign something to index inside data_array? If so, the result will depend on the order of execution (the continuous vs the blocking assign) -- this would explain why using PC directly resolves this.

4 Comments

As seen my wrong waveform example pc comes and assigned combinationally to index wire or logic, inside the data array there is a multiplexer to select ``` assign write_index = flush? flush_index : index;```, and yes second time it is assigned a wire or logic. Is this tw assign statement can be reason race condition?
Difficult to say without a specific snippet. Do you read index or write_index inside an "always @(posdege clk)" block?
Post is updated, I give detailed code block.
pc and clk change asynchronously in top_tb, so the assign to wr_index and the always block for data_o will have indeterminate order. I do not have time to check right now, but if you wait on posedege clk in the tb_top initial block (for instance, change #10 to @(posedge clk)), the issue should disappear. It might also go away if you read index into a register in top, instead of assigning it directly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.