首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Verilog验证单端口RAM

用Verilog验证单端口RAM
EN

Stack Overflow用户
提问于 2021-09-08 20:42:55
回答 2查看 559关注 0票数 0

我为一个端口SRAM编写了一个Verilog测试平台,在地址i上进行写操作,并在i-1地址连续读取它。如下所示

代码语言:javascript
复制
task write_read;
integer i;
begin
 for (i=1,i<=20,i=i+1) begin
  write_mode(i,$urandom);  // i= address, $urandom=data
  read_mode(i-1);  //i-1 address
 end
end
endtask

PS: write_mode、read_mode是设置wen、cs和一些扫描模式引脚以及延迟的任务。

在Verdi波形中,我看到了正确的读写操作。但是,我想验证写入地址的数据与从日志文件读取的地址上的数据相同。如果它们不匹配,则应该显示错误。我不知道如何在代码中实现这一点。当我有数百个编译器时,我无法进入所有的编译器路径,打开它们的波形文件并手动检查读、写操作。

我试图存储特定地址位置的$urandom数据,但每次迭代周期都会覆盖它。我可以使用一个函数来返回$urandom值,但是我的环境包含延迟,所以我不能使用函数。

简单地说,我正在寻找Verilog代码帮助,在没有转储波形的情况下进行内存验证。能帮上忙吗?如果需要更多的细节,请告诉我

谢谢

EN

回答 2

Stack Overflow用户

发布于 2021-09-08 22:07:44

使用Kristen框架,您可以获得一些可重用的测试工作台代码。下面是那个测试平台上的一个名为test_support.vh的文件。该文件包含用于显示错误和计数错误的函数。我建议您在比较内存位置时使用===或!==,因为未定义的信号可能在不经意间匹配。在测试结束时,调用display_test_final_status,这将在日志文件中为您创建一个总体测试报告。在完全回归完成后,您现在可以在日志文件上运行grep,查找错误,它将显示一致的mannor中的任何失败。

我有一个非常喜欢的Perl回归脚本,它运行我所有的测试,自动完成grep,并发送一封成功或失败的电子邮件。

在每个测试的基础上,您将需要设置一些定义来指示测试名称,以及是否希望错误立即停止测试。

祝好运。

代码语言:javascript
复制
// -----------------------------------------------------------
// test_support.vh                                         
// Generated file specifies which numerical test cases to run.                 
// Kristen Software License - Version 1.0 - January 1st, 2019                  
//                                                                             
// Permission is hereby granted, free of charge, to any person or organization 
// obtaining a copy of the software and accompanying documentation covered by  
// this license (the "Software") to use, reproduce, display, distribute,     
// execute, and transmit the Software, and to prepare derivative works of the  
// Software, and to permit third-parties to whom the Software is furnished to  
// do so, all subject to the following:                                        
//                                                                             
// The copyright notices in the Software and this entire statement, including  
// the above license grant, this restriction and the following disclaimer,     
// must be included in all copies of the Software, in whole or in part, and    
// all derivative works of the Software, unless such copies or derivative      
// works are solely in the form of machine-executable object code generated by 
// a source language processor.                                                
//                                                                             
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT   
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE   
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.                                                   
                                                                               
// GENERATED FILE - DO NOT MODIFY THIS FILE MANUALLY.                          
// -----------------------------------------------------------

logic[63:0] error_count = 0;
logic[63:0] lcl_error_count = 0;
logic bool_quick_mode = 0;
logic[511:0] support_test_passes;
logic[15:0] support_test_fails [0:511];
logic[511:0] support_test_was_run;
task test_init;
error_count = 0;     
lcl_error_count = 0; 
endtask

task display_test_begin_status;
    begin 
        
        `ifdef QUICK_MODE
        bool_quick_mode = 1;
        `endif

        $display("=========================================================================");
        $display("| Test: %s    QUICK_MODE = %s", `TEST_NAME_STR, bool_quick_mode ? "ON" : "OFF");
        $display("| VERBOSE = %0d", `VERBOSE);
        $display("=========================================================================");
    end
endtask

task display_test_start;
    input[31:0] test_id;
    input string test_description;

    begin
        lcl_error_count = 0;
        $display("=========================================================================");
        $display("%0t: Test %0d : %s.", $time, test_id, test_description);
        $display("=========================================================================");
    end
endtask

task display_test_end;
    input[31:0] test_id;
    begin
        $display("=========================================================================");
        $display("%0t: Test %0d Complete with %0d ERRORS.", $time, test_id, lcl_error_count);
        $display("=========================================================================");
        support_test_was_run[test_id] = 1'b1;
        if (lcl_error_count == 0) 
            support_test_passes[test_id] = 1'b1;
        else
            support_test_fails[test_id] = lcl_error_count;
    end
endtask

task display_error_inc;
    input string error_description;
    begin
       error_count++;
       lcl_error_count++;
       //$display("=========================================================================");
       $display("%0t: ERROR:  %s : error_count: %0d",$time, error_description, error_count );
       //$display("=========================================================================");
       `ifdef TEST_STOP_ON_ERROR
        if (error_count >= `TEST_STOP_ON_ERROR_LIMIT) begin
            $display("%0t, Stopping on error count = %d, %m", $time, error_count); 
            $finish();
        end
       `endif
    end
endtask

task display_test_final_status;
    //input string testname;
    begin
       $display("=========================================================================");
       $display("%0t: Test %s %s with %0d ERRORS",$time, `TEST_NAME_STR, error_count > 0 ? "FAILS" : "PASSES",error_count);
       $display("=========================================================================");
       if (error_count !== 'h0)
           begin
              $display("Test failures:");
              for (int err_fail_cnt = 0;err_fail_cnt < 512; err_fail_cnt = err_fail_cnt + 1)
                  begin
                      if (support_test_was_run[err_fail_cnt] == 1'b1 && support_test_passes[err_fail_cnt] != 1'b1)
                          begin
                             $display("Test %d, fails with %d errors", err_fail_cnt, support_test_fails[err_fail_cnt]);
                          end
                  end
           end
    end
endtask

task display_no_test_found;
    input[31:0] test_id;
    input string test_description;

    begin
        lcl_error_count = 0;
        $display("=========================================================================");
        $display("%0t: Test %0d : %s NOT FOUND SKIPPING.", $time, test_id, test_description);
        $display("=========================================================================");
    end
endtask

在Kristen生成的测试平台上,当检测到RAM单元时,这就是正在运行的测试。我认为这是一种算法解决方案,因为您必须生成几个向量字符串和其他函数,将这些字符串转换为地址。

xreg_v1___write_mpi_test是写入RAM的任务,xreg_v1___read_mpi_test是从RAM读取的任务。有一个比较任务xreg_v1___register_compare_with_error,它显然会生成一个错误。我也会在下面展示这些。

代码语言:javascript
复制
    // This is a casex snippet from the RAM test
   7'd2: begin
         // xreg_v1_0_0_mem_ack test
         $display("%0t, xreg_v1_0_0_mem_ack test", $time);
         oo_limit = get_entries_by_index(tc_index) > 256 ? 256 : get_entries_by_index(tc_index);  //Max number of entries for this test
         mm_step  = get_entry_offset(tc_index);
         nn_limit = perfect_by_datawidth(get_size_by_index(get_address_by_index(tc_index)),DATAPATH_WIDTH)/8; // Number of bytes for this entry
         nn_step = DATAPATH_WIDTH == 8  ? 1 : DATAPATH_WIDTH == 16 ? 2 : DATAPATH_WIDTH == 32 ? 4 : 8;
         for(oo = 0; oo < oo_limit; oo = oo + 1) // Move through each entry we will be testing
         begin
            for (nn = 0; nn < nn_limit; nn = nn + nn_step) // Walk through each access of a given entry
            begin
            test_address = get_address_by_index(tc_index) + (oo*mm_step) + nn;
            expected = oo[7:0] ^ nn[7:0] ^ mm_step[7:0] ^ nn_step[7:0]; 
        expected = {expected[6:0],expected[7],expected[2:0],expected[7:3],expected[5],expected[3],expected[1],expected[7],expected[0],expected[2],expected[6],expected[4],expected[7:0]};
            xreg_v1_0_0_write_mpi_test(aclk, test_address, expected);
            end
         end
         for(oo = 0; oo < oo_limit; oo = oo + 1) // Move through each entry we will be testing
         begin
            for (nn = 0; nn < nn_limit; nn = nn + nn_step) // Walk through each access of a given entry
            begin
            test_address = get_address_by_index(tc_index) + (oo*mm_step) + nn;
        mask = get_entry_mask_by_index(tc_index);
            expected = oo[7:0] ^ nn[7:0] ^ mm_step[7:0] ^ nn_step[7:0]; 
        expected = {expected[6:0],expected[7],expected[2:0],expected[7:3],expected[5],expected[3],expected[1],expected[7],expected[0],expected[2],expected[6],expected[4],expected[7:0]} & (get_entry_mask_by_index(tc_index) >> (nn*8));
            xreg_v1_0_0_read_mpi_test(aclk, test_address, result);
            xreg_v1_0_0_register_compare_with_error(test_address,expected,result);
            end
         end
    end

下面是一些引用的任务,显示写入、读取和比较已实现的内容。我认为其中一些是系统Verilog,所以你必须把它当作算法来处理。

代码语言:javascript
复制
task automatic xreg_v1_0_0_read_mpi_test;
    ref logic clock;
    input  [`TEST_ADDR_WIDTH-1:0] address;
    output [`TEST_DATA_WIDTH-1:0] result;
    begin
        $display("ENTER >>> xreg_v1_0_0_read_mpi_test");
        repeat(1) @(posedge clock);
        `TEST_MPI_ADDR = address;
        `TEST_MPI_RD_REQ = 1'b1;
        `TEST_MPI_ENABLE = 1'b1;
        while (!`TEST_MPI_ACK) repeat(1) @(posedge clock);
        `TEST_MPI_ADDR = 'h0;
        `TEST_MPI_RD_REQ = 1'b0;
        `TEST_MPI_ENABLE = 1'b0;
        result = `TEST_MPI_RD_DATA;
        $display("WAITING ACK <<< xreg_v1_0_0_read_mpi_test");
        while (`TEST_MPI_ACK) repeat(1) @(posedge clock);
        $display("EXIT <<< xreg_v1_0_0_read_mpi_test");
    end
endtask

task automatic xreg_v1_0_0_write_mpi_test;
    ref logic clock;
    input  [`TEST_ADDR_WIDTH-1:0] address;
    input [`TEST_DATA_WIDTH-1:0]  data;
    begin
        $display("ENTER >>> xreg_v1_0_0_write_mpi_test");
        repeat(1) @(posedge clock);
        `TEST_MPI_ADDR = address;
        `TEST_MPI_WR_DATA = data;
        `TEST_MPI_WR_REQ = 1'b1;
        `TEST_MPI_ENABLE = 1'b1;
        while (!`TEST_MPI_ACK) repeat(1) @(posedge clock);
        `TEST_MPI_ADDR = 'h0;
        `TEST_MPI_WR_DATA = 'h0;
        `TEST_MPI_WR_REQ = 1'b0;
        `TEST_MPI_ENABLE = 1'b0;
        $display("WAITING ACK <<< xreg_v1_0_0_write_mpi_test");
        while (`TEST_MPI_ACK) repeat(1) @(posedge clock);
        $display("EXIT <<< xreg_v1_0_0_write_mpi_test");
    end
endtask

task automatic xreg_v1_0_0_register_compare_with_error;
    input [`TEST_ADDR_WIDTH-1:0] address;
    input [`TEST_DATA_WIDTH-1:0] expected;
    input [`TEST_DATA_WIDTH-1:0] result;
    begin
        $display("ENTER >>> xreg_v1_0_0_register_compare_with_error");
        if (expected !== result)
            begin 
            $display("%0t, Address = 0x%X", $time, address);
            $display("%0t, Expected 0x%X", $time, expected);
            $display("%0t, Read     0x%X", $time, result);
            display_error_inc("xreg_v1_0_0_rdconst_test: Mismatch between read and expected data.");
            end
        $display("EXIT <<< xreg_v1_0_0_register_compare_with_error");
    end
endtask
票数 0
EN

Stack Overflow用户

发布于 2021-09-09 06:39:02

首先要将写入数据存储在队列中。然后,在读取SRAM时,将地址传递给队列,并比较queue_data_out和sram_data_out。如果比较失败,则打印错误。见下面的伪代码。

代码语言:javascript
复制
task write_read;
integer i;
bit write_data_queue [$];
begin
 for (i=1,i<=20,i=i+1) begin
  write_mode(i,$urandom);  // i= address, $urandom=data

  write_data_queue.push_front($urandom);

  read_mode(i-1);  //i-1 address

  queue_data = write_data_queue.pop_front();

  if(queue_data != read_mode(i-1))
   $display("ERROR'\n")

 end
end
endtask
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69109436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档