我为一个端口SRAM编写了一个Verilog测试平台,在地址i上进行写操作,并在i-1地址连续读取它。如下所示
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
endtaskPS: write_mode、read_mode是设置wen、cs和一些扫描模式引脚以及延迟的任务。
在Verdi波形中,我看到了正确的读写操作。但是,我想验证写入地址的数据与从日志文件读取的地址上的数据相同。如果它们不匹配,则应该显示错误。我不知道如何在代码中实现这一点。当我有数百个编译器时,我无法进入所有的编译器路径,打开它们的波形文件并手动检查读、写操作。
我试图存储特定地址位置的$urandom数据,但每次迭代周期都会覆盖它。我可以使用一个函数来返回$urandom值,但是我的环境包含延迟,所以我不能使用函数。
简单地说,我正在寻找Verilog代码帮助,在没有转储波形的情况下进行内存验证。,能帮上忙吗?如果需要更多的细节,请告诉我
谢谢
发布于 2021-09-08 22:07:44
使用Kristen框架,您可以获得一些可重用的测试工作台代码。下面是那个测试平台上的一个名为test_support.vh的文件。该文件包含用于显示错误和计数错误的函数。我建议您在比较内存位置时使用===或!==,因为未定义的信号可能在不经意间匹配。在测试结束时,调用display_test_final_status,这将在日志文件中为您创建一个总体测试报告。在完全回归完成后,您现在可以在日志文件上运行grep,查找错误,它将显示一致的mannor中的任何失败。
我有一个非常喜欢的Perl回归脚本,它运行我所有的测试,自动完成grep,并发送一封成功或失败的电子邮件。
在每个测试的基础上,您将需要设置一些定义来指示测试名称,以及是否希望错误立即停止测试。
祝好运。
// -----------------------------------------------------------
// 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,它显然会生成一个错误。我也会在下面展示这些。
// 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,所以你必须把它当作算法来处理。
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发布于 2021-09-09 06:39:02
首先要将写入数据存储在队列中。然后,在读取SRAM时,将地址传递给队列,并比较queue_data_out和sram_data_out。如果比较失败,则打印错误。见下面的伪代码。
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
endtaskhttps://stackoverflow.com/questions/69109436
复制相似问题