同步RAM相关

发布于 2025-01-30 15:04:46 字数 4024 浏览 1 评论 0原文

我正在尝试模拟Verilog中同步RAM的以下代码。

当我试图在特定地址中写入时, dataout 并不是我期望的方式。在指定地址中读取数据时,它会跳过1个地址。

有人可以告诉我这个问题吗?

这是Gtkwave仿真结果:

”“

module ram 
  # (parameter ADDR_WIDTH = 4,
     parameter DATA_WIDTH = 10,
     parameter DEPTH = 1 <<  ADDR_WIDTH
    )
  
  (     input                   clk,
        input [ADDR_WIDTH-1:0]  addr,
        input [DATA_WIDTH-1:0]  dataIn,
        input                   enable,
        input                   write,
        input                   read,
      input           resetRam, 
      output[DATA_WIDTH-1:0]  dataOut  
  );
  
  reg [DATA_WIDTH-1:0]  tmp_data;
  reg [DATA_WIDTH-1:0]  mem [DEPTH-1:0];

  //reset 
  always @(posedge clk) begin 
    if(enable & resetRam) begin
      for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1)
      begin
        mem[i] = {DATA_WIDTH{1'b0}};
      end
    end
  end
  
  //write
  always @ (posedge clk) begin
    if (enable & write & !read)
      mem[addr] <= dataIn;
  end
  
  //read
  always @ (posedge clk) begin
    if (enable & !write & read)
        tmp_data <= mem[addr];
  end
  
  assign dataOut = enable & read & !write ? tmp_data : 'hz || enable & resetRam ? 10'b0 : 'hz;
  
endmodule

module ram_tb;
  parameter ADDR_WIDTH = 4;
  parameter DATA_WIDTH = 10;
  parameter DEPTH = 1 << ADDR_WIDTH;
  
  reg clk;
  reg enable;
  reg write;
  reg read;
  reg resetRam;
  reg [ADDR_WIDTH-1:0] addr;
  wire [DATA_WIDTH-1:0] dataIn;
  wire [DATA_WIDTH-1:0] dataOut;
  reg [DATA_WIDTH-1:0] tb_data;
  
  ram #(.DATA_WIDTH(DATA_WIDTH)) iram(
                          .clk(clk),
                            .addr(addr),
                            .dataIn(dataIn),
                            .enable(enable),
                                      .write(write),
                                      .read(read),
                          .resetRam(resetRam),
                          .dataOut(dataOut)
                         );
  
  
  always #10 clk = ~clk;
  assign dataIn = !read ? tb_data : 'hz ;
  
  
  initial begin
    $monitor("addrs = %b resetRam=%b Write = %b  read=%b dataIn = %b dataOut = %b", addr,resetRam,write,read,dataIn,dataOut);
    $dumpfile("ram_tb.vcd");
    $dumpvars(0,ram_tb);

    {clk, enable, write, addr, tb_data, read,resetRam} <= 0;
    


    // //writing all the adrress with random value
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  @(posedge clk) addr <= i; write = 1; enable =1; read = 0; tb_data <= $random;
    // end


    // //reading them
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  @(posedge clk) addr = i; write = 0; enable = 1; read = 1;
    // end


     //Writing at specific address
    @(posedge clk) addr = 4'b1000; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b1111; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b1001; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b0001; write = 1; enable =1; read = 0; tb_data <= $random;  

    

    //reading them
    @(posedge clk) addr = 4'b1000;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b1111;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b1001;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b0001;write = 0; enable =1; read = 1;
    

    

    // //reset memory
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  repeat (1) @(posedge clk) addr <= i; enable <= 1; resetRam <=1;
    // end


    
    #200 $finish;
  end
endmodule

//iverilog -o ram_tb.vpp ram.v
//vvp ram_tb.vpp

I am trying to simulate the following code for an synchronous ram in Verilog.

When I am trying to write in a specific address, dataOut is not coming the way I was expecting. It is skipping 1 address while reading data in the specified address.

enter image description here

Can anyone tell me the problem?

Here is GtkWave simulation result:

module ram 
  # (parameter ADDR_WIDTH = 4,
     parameter DATA_WIDTH = 10,
     parameter DEPTH = 1 <<  ADDR_WIDTH
    )
  
  (     input                   clk,
        input [ADDR_WIDTH-1:0]  addr,
        input [DATA_WIDTH-1:0]  dataIn,
        input                   enable,
        input                   write,
        input                   read,
      input           resetRam, 
      output[DATA_WIDTH-1:0]  dataOut  
  );
  
  reg [DATA_WIDTH-1:0]  tmp_data;
  reg [DATA_WIDTH-1:0]  mem [DEPTH-1:0];

  //reset 
  always @(posedge clk) begin 
    if(enable & resetRam) begin
      for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1)
      begin
        mem[i] = {DATA_WIDTH{1'b0}};
      end
    end
  end
  
  //write
  always @ (posedge clk) begin
    if (enable & write & !read)
      mem[addr] <= dataIn;
  end
  
  //read
  always @ (posedge clk) begin
    if (enable & !write & read)
        tmp_data <= mem[addr];
  end
  
  assign dataOut = enable & read & !write ? tmp_data : 'hz || enable & resetRam ? 10'b0 : 'hz;
  
endmodule

module ram_tb;
  parameter ADDR_WIDTH = 4;
  parameter DATA_WIDTH = 10;
  parameter DEPTH = 1 << ADDR_WIDTH;
  
  reg clk;
  reg enable;
  reg write;
  reg read;
  reg resetRam;
  reg [ADDR_WIDTH-1:0] addr;
  wire [DATA_WIDTH-1:0] dataIn;
  wire [DATA_WIDTH-1:0] dataOut;
  reg [DATA_WIDTH-1:0] tb_data;
  
  ram #(.DATA_WIDTH(DATA_WIDTH)) iram(
                          .clk(clk),
                            .addr(addr),
                            .dataIn(dataIn),
                            .enable(enable),
                                      .write(write),
                                      .read(read),
                          .resetRam(resetRam),
                          .dataOut(dataOut)
                         );
  
  
  always #10 clk = ~clk;
  assign dataIn = !read ? tb_data : 'hz ;
  
  
  initial begin
    $monitor("addrs = %b resetRam=%b Write = %b  read=%b dataIn = %b dataOut = %b", addr,resetRam,write,read,dataIn,dataOut);
    $dumpfile("ram_tb.vcd");
    $dumpvars(0,ram_tb);

    {clk, enable, write, addr, tb_data, read,resetRam} <= 0;
    


    // //writing all the adrress with random value
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  @(posedge clk) addr <= i; write = 1; enable =1; read = 0; tb_data <= $random;
    // end


    // //reading them
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  @(posedge clk) addr = i; write = 0; enable = 1; read = 1;
    // end


     //Writing at specific address
    @(posedge clk) addr = 4'b1000; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b1111; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b1001; write = 1; enable =1; read = 0; tb_data <= $random;
    @(posedge clk) addr = 4'b0001; write = 1; enable =1; read = 0; tb_data <= $random;  

    

    //reading them
    @(posedge clk) addr = 4'b1000;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b1111;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b1001;write = 0; enable =1; read = 1;
    @(posedge clk) addr = 4'b0001;write = 0; enable =1; read = 1;
    

    

    // //reset memory
    // for (integer i = 0; i < DEPTH; i= i+1) begin
    //  repeat (1) @(posedge clk) addr <= i; enable <= 1; resetRam <=1;
    // end


    
    #200 $finish;
  end
endmodule

//iverilog -o ram_tb.vpp ram.v
//vvp ram_tb.vpp

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄居者 2025-02-06 15:04:46

你有种族状况。您应该在设计和所有同步信号的测试台中使用非块分配(&lt; =)。

在设计中,更改:

    mem[i] = {DATA_WIDTH{1'b0}};

TO:在:

    mem[i] <= {DATA_WIDTH{1'b0}};

在测试台上,使用:

 //Writing at specific address
@(posedge clk) addr <= 4'b1000; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b1111; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b1001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b0001; write <= 1; enable <=1; read <= 0; tb_data <= $random;  

//reading them
@(posedge clk) addr <= 4'b1000;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b1111;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b1001;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b0001;write <= 0; enable <=1; read <= 1;

随着上述更改,我在

You have a race condition. You should use nonblocking assignments (<=) in your design and testbench for all synchronous signals.

In the design, change:

    mem[i] = {DATA_WIDTH{1'b0}};

to:

    mem[i] <= {DATA_WIDTH{1'b0}};

In the testbench, use:

 //Writing at specific address
@(posedge clk) addr <= 4'b1000; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b1111; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b1001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
@(posedge clk) addr <= 4'b0001; write <= 1; enable <=1; read <= 0; tb_data <= $random;  

//reading them
@(posedge clk) addr <= 4'b1000;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b1111;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b1001;write <= 0; enable <=1; read <= 1;
@(posedge clk) addr <= 4'b0001;write <= 0; enable <=1; read <= 1;

With the above changes, I get your expected output with iverilog on edaplayground.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文